I am using class Based view for update my Blog post but validation error message not showing in my Django template html. Here is my code:
froms.py
from .models import *
from django import forms
from django.core.exceptions import ValidationError
class BlogPost(forms.ModelForm):
class Meta:
model = Post
fields = ['title','author','body']
widgets = {
'title': forms.TextInput(attrs={'class':'form-control'}),
'author': forms.Select(attrs={'class':'form-control'}),
'body': RichTextField(),
}
def clean(self):
cleaned_data = super(BlogPost,self).clean()
title = cleaned_data.get('title')
if title:
if title(name)<30:
count_text = len(title)
raise ValidationError("Title is too short")
views.py
class blog_update_view(UpdateView):
model = Post
template_name = "blog_update_post.html"
form_class = BlogPost
html
{% form.non_field_errors %}
<form method="POST">
{% csrf_token %}
{{form.media}}
{{form.as_p}}
<button class="btn btn-info">Publish</button>
</form>
</div>
I also want to know how to handle others error in django-form such as integrityerror in class based view.
Your function is not properly indented, you should place this in the scope of the .clean(…) method:
class BlogPost(forms.ModelForm):
class Meta:
model = Post
fields = ['title','author','body']
widgets = {
'title': forms.TextInput(attrs={'class':'form-control'}),
'author': forms.Select(attrs={'class':'form-control'}),
'body': RichTextField(),
}
def clean(self):
cleaned_data = super().clean()
title = cleaned_data.get('title')
if title:
if len(title) < 30:
count_text = len(title)
raise ValidationError("Title is too short")
return cleaned_data
But it makes more sense here to put in in the clean_title method, since then it is attached to the title field:
class BlogPost(forms.ModelForm):
class Meta:
model = Post
fields = ['title','author','body']
widgets = {
'title': forms.TextInput(attrs={'class':'form-control'}),
'author': forms.Select(attrs={'class':'form-control'}),
'body': RichTextField(),
}
def clean_title(self):
title = self.cleaned_data['title']
if title and len(title) < 30:
raise ValidationError("Title is too short")
return title
A CharField [Django-doc] has a min_length=… [Django-doc] that can be used:
class BlogPost(forms.ModelForm):
title = forms.CharField(
min_length=30,
widget=forms.TextInput(attrs={'class':'form-control'})
)
class Meta:
model = Post
fields = ['title','author','body']
widgets = {
'author': forms.Select(attrs={'class':'form-control'}),
'body': RichTextField(),
}
Related
in my form i want to select department from 2 options: some object(every time only one) and None.
my form.py
class TeamGoalForm(ModelForm):
def __init__(self, *args, **kwargs):
employees = kwargs.pop('employees')
department = kwargs.pop('department')
super().__init__(*args, **kwargs)
self.fields['employees'].queryset = employees
self.fields['department'].choices = [(1, department), (2, None)]
self.fields['department'].initial = [1]
class Meta:
model = TeamGoal
fields = ('team_goal_title','department','employees', 'team_goal_description', 'gpd_year','team_factor_0','team_factor_1','team_factor_2','team_factor_3','team_factor_weight')
widgets = {
'team_goal_title': forms.TextInput (attrs={'class':'form-control', 'placeholder':'Enter the title of goal'}),
'department': forms.Select (attrs={'class': 'form-control', 'placeholder':'Select department'}), }
in my view.py I have had:
if request.method == 'POST':
form = TeamGoalForm(request.POST, employees=employees, department=department)
if form.is_valid():
form.save()
Here my department is an object.
How to implement something like this, 'cos my solution does't work?
You are not showing much of the code, but here is more or less how the different files should look like, hope this helps:
**#models.py**
from django.db import models
class department(models.Model):
# department fields
pass
class TeamGoal(models.Models):
...
deparment = models.ForeignKey(department, on_delete=models.CASCADE)
...
**#forms.py**
from django.forms import ModelForm
from django import forms
class TeamGoalForm(ModelForm):
class Meta:
model = TeamGoal
fields = (
'team_goal_title',
'department',
'employees',
'team_goal_description',
'gpd_year',
'team_factor_0',
'team_factor_1',
'team_factor_2',
'team_factor_3',
'team_factor_weight'
)
deparments = deparment.objects.all()
widgets = {
'deparments': forms.Select(choices=deparments,
attrs={
'class': 'form-control',
'placeholder':'Select department'
})
**#views.py**
from .forms import TeamGoalForm
def AddTeamGoalForm(request):
context = {
'TeamGoalForm': TeamGoalForm,
}
if request.method == 'POST':
addTeamGoalForm = TeamGoalForm(request.POST)
if addTeamGoalForm.is_valid():
newTeamGoalForm = addTeamGoalForm.save()
return redirect('/')
else:
return render(request, '/TeamGoalForm.html', context)
**# TeamGoalForm.html**
<form method="POST">
{% csrf_token %}
{{ TeamGoalForm}}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
NOTE: you may need to adjust it based on the code you've already writen, but hopefully this leads close to a solution.
I get an error when I try to add a widget to the form.
The error:
File "C:\Users\lib\site-packages\django\forms\fields.py", line 558, in __init__
super().__init__(**kwargs)
TypeError: __init__() got an unexpected keyword argument 'attrs'
The model
class Video(models.Model):
author = models.ForeignKey(Account, on_delete=models.CASCADE)
video = models.FileField(upload_to='post-videos')
title = models.CharField(max_length=100)
description = models.TextField(null=True, blank=True)
video_poster = models.ImageField(max_length=255, upload_to='post-videos')
The views
def VideosUploadView(request, *args, **kwargs):
all_videos = Video.objects.all()
V_form = Video_form()
video_added = False
if not request.user.is_active:
# any error you want
return redirect('login')
try:
account = Account.objects.get(username=request.user.username)
except:
# any error you want
return HttpResponse('User does not exits.')
if 'submit_v_form' in request.POST:
print(request.POST)
V_form = Video_form(request.POST, request.FILES)
if V_form.is_valid():
instance = V_form.save(commit=False)
instance.author = account
instance.save()
V_form = Video_form()
video_added = True
contex = {
'all_videos': all_videos,
'account': account,
'V_form': V_form,
'video_added': video_added,
}
return render(request, "video/upload_videos.html", contex)
The form
class Video_form(forms.ModelForm):
class Meta:
model = Video
fields = ('title', 'description', 'video', 'video_poster')
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.TextInput(attrs={'class': 'form-control'}),
'video': forms.FileField(widget=forms.FileInput(attrs={'class': 'form-control'})),
'video_poster': forms.ImageField(attrs={'class': 'form-control'}),
}
You must assign valid widget in the Video_form:
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.TextInput(attrs={'class': 'form-control'}),
'video': forms.FileInput(attrs={'class': 'form-control'}),
'video_poster': forms.ClearableFileInput(attrs={'class': 'form-control'}),
}
forms.FileField and forms.ImageField are fields not widgets.
My problem was style the form fields and I explored a good way to styling the fields by add the field name after the form name
Like this way
<span class="control-fileupload">
<!--here what I mean--> {{ V_form.video }}
<label for="file1" class="text-left">click to choose a Video on your computer.</label>
</span>
and here also
<label>{{ V_form.title }}</label>
I want to when i click on the user discharge button it will go to the page and the all user information take automatically. But i cannot get this value. Here is the image in the discharge button i click but its shows like this.
Here is my code : views.py
def discharge_view(request, pk):
form = DischargForm()
if request.method == 'POST':
form = DischargForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Successfull')
return redirect('discharge-patient')
context = {
'form': form,
}
return render(request, 'hospital/discharge.html', context)
forms.py :
class DischargForm(forms.ModelForm):
class Meta:
model = PatientDischarge
fields = ('assign_doctor', 'admitted', 'release_date', 'medicine_cost', 'other_charge')
widgets = {
'assign_doctor': forms.Select(attrs={'class': 'form-control'}),
'admitted': forms.Select(attrs={'class': 'form-control'}),
'release_date': forms.TextInput(attrs={'class': 'form-control'}),
'medicine_cost': forms.TextInput(attrs={'class': 'form-control'}),
'other_charge': forms.TextInput(attrs={'class': 'form-control'}),
}
models.py
class PatientDischarge(models.Model):
assign_doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
admitted = models.ForeignKey(Admitted, on_delete=models.CASCADE)
release_date = models.DateField(auto_now_add=False)
medicine_cost = models.IntegerField(null=True)
other_charge = models.IntegerField()
def __str__(self):
return self.admitted.patient_name if all([self.admitted, self.admitted.patient_name]) else 0
def days_count(self):
return self.release_date - self.admitted.admited_date if all([self.admitted, self.admitted.admited_date]) else 0
def room_bill(self):
return self.days_count() * self.admitted.room_service if all([self.admitted, self.admitted.room_service]) else 0
def total_bill(self):
return self.room_bill().days + self.medicine_cost + self.other_charge
discharge.html
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% for fields in form %}
<div class="form-group"></div>
{{ fields.label_tag }}
{{ fields }}
{% endfor %}
<br>
<input type="submit" value="Submit">
To pass an instance to the form you can do this form = DischargForm(instance=<DischargeInstance>) and the template will have pre-filled values in the form as per the instance.
Can you provide your models.py.
I have created a form and a view in Django and I'm trying to display it in the HTML but it isn't loading anything and I don't know why.
alumno2.html
{% block header %}
<header class="masthead bg-white text-dark text-uppercase">
<div class="container">
<h3 class="text-center">Añadir alumno</h3>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-secondary" type="submit">Guardar</button>
</form>
</div>
</header>
{% endblock %}
form.py
class AlumnoForm2(forms.ModelForm):
class Meta:
model = Alumno
#fields = ['dni', 'nombre', 'apellido1', 'apellido2','email','repetidor']
fields = ['dni', 'nombre', 'apellido1', 'apellido2','email','repetidor','curs']
labels = {
'dni': 'dni',
'nombre': 'nombre',
'apellido1': 'Primer Apellido',
'apellido2': 'Segundo Apellido',
'email': 'Email',
'repetidor': 'repetidor',
'curs': 'curs'
}
widgets = {
'dni': forms.TextInput(attrs={'class': 'form-control'}),
'nombre': forms.TextInput(attrs={'class': 'form-control'}),
'apellido1': forms.TextInput(attrs={'class': 'form-control'}),
'apellido2': forms.TextInput(attrs={'class': 'form-control'}),
'email': forms.TextInput(attrs={'class': 'form-control'}),
'repetidor': forms.CheckboxInput(attrs={'class':'form-control-checkbox','id': 'repetidor'}),
'curs':forms.Select(attrs={'class': 'form-control'}),
}
view.py
class crea_alumno(CreateView):
model = Alumno
form_class = AlumnoForm2
template_name = '/alumno2.html'
success_url = reverse_lazy('mostrar_alumnos')
url.py
url(r'^alumno2/$', crea_alumno.as_view(),name='alumno2'),
models.py
class Alumno(models.Model):
dni = models.CharField(max_length=9,primary_key=True)
nombre = models.CharField(max_length=100)
apellido1 = models.CharField('Primer apellido',max_length=50)
apellido2 = models.CharField('Segundo apellido',max_length=50)
email = models.EmailField("Correo electronico",null=True)
repetidor = models.BooleanField()
curs = models.ManyToManyField(Curso, blank=True, related_name="Historico_de_cursos")
Nivel = models.ManyToManyField('Nivel', through = 'Completado',through_fields=('Alumno','Nivel'))
Practica = models.ManyToManyField('Practica', through = 'Nota',through_fields=('Alumno','Practica'))
Curso = models.ManyToManyField('Curso',through = 'Curso_alumno',through_fields=('Alumno','Curso'))
def __str__(self):
return self.dni
the html only display the save button, is not loading the create form. The html is inside the template folders thats why I have this urls.
EDIT:
I have removed the template I had also
url(r'^alumno2/$', TemplateView.as_view(template_name='alumno2.html'),name='alumno2'),
and I'm not sure if i need to put this in the url.py so now I only have the view and is unable to find my template withouth that
Remove the line
url(r'^alumno2/$', TemplateView.as_view(template_name='alumno2.html'),name='alumno2'),
from your urls.py and only keep this one:
url(r'^alumno2/$', crea_alumno.as_view(),name='alumno2'),
And inside your view, remove the / in the template name: instead of
template_name = '/alumno2.html'
Use
template_name = 'alumno2.html'
And replace CreateView with FormView as per the documentation
I have a template in which I edit all the basic fields of a model User.
Now I want to have a form in which there will be displayed all available permissions in a checkbox-like style. The ones already assigned to the User should already be checked.
I have a form.py, with a form for editing User, but have not completed the permissions form.
class UserSettingsForm(forms.ModelForm):
class Meta:
model = User
fields = (
'username',
'first_name',
'last_name',
'email',
'urnik',
'ure_na_teden',
'rfid',
'oddelek',
'status_zaposleni',
)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(UserSettingsForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
self.fields['username'].disabled = True
def save(self):
user = super(UserSettingsForm, self).save()
return user
class UserPermissonsForm(forms.ModelForm):
class Meta:
model = Permission
fields = (
'name',
'content_type',
'codename',
)
And a views.py:
#login_required
def uporabnik_uredi(request, username=None):
user = get_object_or_404(User, username=username)
uporabnik_form = UserSettingsForm(request.POST or None,request=request, instance=user)
permissions = [(p.id, p.name) for p in Permission.objects.filter(user=user)]
data = {
'uporabnik' : user,
'form' : uporabnik_form,
'from': request.GET.get('from', None),
'permissions' : permissions,
}
if request.POST:
if uporabnik_form.is_valid():
user = uporabnik_form.save()
next = request.GET.get('next', None)
return redirect(next)
return render(request, "sifranti/uporabniki/uredi.html", data)
And also a template, just to see which current permissions are assigned to the user:
<div class="">
{% for id, name in permissions %}
{{ id }} - {{ name }} <br>
{% endfor %}
</div>
This is how I do but i use a MultipleSelect, I guess you can apply some of this to checkboxes.
class EditUserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(EditUserForm, self).__init__(*args, **kwargs)
def get_label(obj):
permission_name = str(obj).split('|')[2].strip()
model_name = permission_name.split(' ')[2].strip()
return '%s | %s' % (model_name.title(), permission_name)
User = get_user_model()
content_type = ContentType.objects.get_for_model(User)
self.fields['user_permissions'].queryset = Permission.objects.filter(content_type=content_type)
self.fields['user_permissions'].widget.attrs.update({'class': 'permission-select'})
self.fields['user_permissions'].help_text = None
self.fields['user_permissions'].label = "Label"
self.fields['user_permissions'].label_from_instance = get_label
def save(self, commit=True):
user_instance = super(EditUserForm, self).save(commit)
user_instance.save()
user_instance.user_permissions.set(self.cleaned_data.get('user_permissions'))
return user_instance
class Meta:
model = get_user_model()
fields = ['email', 'first_name', 'last_name', 'user_permissions']
widgets = {
'email': forms.EmailInput(attrs={'class': 'form-control', 'style': 'width: 300px;'}),
'first_name': forms.TextInput(attrs={'class': 'form-control', 'style': 'width: 300px;'}),
'last_name': forms.TextInput(attrs={'class': 'form-control', 'style': 'width: 300px;'}),
'user_permissions': forms.SelectMultiple(attrs={'style': 'width: 350px; height: 200px;'})
}
Hope this helps, good luck!