I'm running a unit test for a Django form, and form.is_valid() keeps returning False and I cannot find the error.
Here's the code for forms.py:
class CustomClearableFileInput(forms.ClearableFileInput):
template_name = 'forums/templates/clearable_file_input.html'
class NewQuestionForm(forms.ModelForm):
category = forms.ModelChoiceField(widget = forms.Select(attrs = {}),
queryset = FossCategory.objects.order_by('name'),
empty_label = "Select a Foss category",
required = True,
error_messages = {'required':'Select a category'})
title = forms.CharField(widget = forms.TextInput(),
required = True,
error_messages = {'required':'Title field required'},
strip=True)
body = forms.CharField(widget = forms.Textarea(),
required = True,
error_messages = {'required':'Question field required'},
strip=True)
is_spam = forms.BooleanField(required = False)
spam_honeypot_field = HoneypotField()
image = forms.ImageField(widget = CustomClearableFileInput(), help_text = "Upload image", required = False)
def clean_title(self):
title = str(self.cleaned_data['title'])
if title.isspace():
raise forms.ValidationError("Title cannot be only spaces")
if len(title) < 12:
raise forms.ValidationError("Title should be longer than 12 characters")
if Question.objects.filter(title = title).exists():
raise forms.ValidationError("This title already exist.")
return title
def clean_body(self):
body = str(self.cleaned_data['body'])
if body.isspace():
raise forms.ValidationError("Body cannot be only spaces")
if len(body) < 12:
raise forms.ValidationError("Body should be minimum 12 characters long")
body = body.replace(' ', ' ')
body = body.replace('<br>', '\n')
return body
class Meta(object):
model = Question
fields = ['category', 'title', 'body', 'is_spam', 'image']
And here's the code for tests.py:
class NewQuestionFormTest(TestCase):
#classmethod
def setUpTestData(cls):
FossCategory.objects.create(name = 'TestCategory', email = 'example#example.com')
def test_too_short_title(self):
category = FossCategory.objects.get(name = "TestCategory")
title = 'shorttitlefsodzo'
form = NewQuestionForm(data = {'category': category, 'title': title, 'body': 'Test question body'})
self.assertTrue(form.is_valid())
This is what I get with print(form.errors):
<ul class="errorlist"><li>category<ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul></li>
Since it's a model choice field, try using the primary key of the category instead of the instance itself.
form = NewQuestionForm(data = {'category': category.pk, 'title': title, 'body': 'Test question body'})
Related
I would like to make two fields (repertoire and performer) required only if the user selects and submits a type="performance". This is my model:
class Event(models.Model):
EV_TYPE = (
('performance', 'performance'),
('other', 'other'),
)
title = models.CharField(max_length=200)
type = models.CharField(max_length=15, choices=EV_TYPE, default="performance")
repertoire = models.ManyToManyField(Work, blank=True)
performer = models.ManyToManyField(Profile, limit_choices_to={'role__type__contains': 'Performer'})
My form:
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = [
'type',
'submitted_by',
'title',
'repertoire',
]
My view:
def event_create_view(request):
if request.method == 'POST':
form_event = EventForm(
request.POST,
repertoire_required=(not (active_user.id == 17)), # if the user is NMS then the repertoire field is not compulsory
initial={'submitted_by' : active_user.profile.id}
)
form_venue = AddVenueForm()
form_profile = ProfileForm()
form_work = WorkFromEventForm()
if form_event.is_valid():
this_event = form_event.save()
return redirect('event-edit', id=this_event.id)
This is what I tried. In the above 'form_event.is_valid', I did:
if form_event.is_valid():
this_event = form_event.save(commit=False)
if this_event['type'] == 'performance' and this_event['performer'] and this_event['repertoire']:
this_event.save()
return redirect('event-edit', id=this_event.id)
This doesn't work though (I still get a 'this field is required' when I submit). How can I achieve what I want to do?
Addendum
This is also not working:
if
this_event['type'] == 'performance' and not this_event['performer'] or not this_event['repertoire']:
messages.error(request, form_event.errors)
else:
this_event.save()
You do that with a clean method on the form.
For example you might do;
def clean(self):
"""
Validate the form input
"""
cleaned_data = super().clean()
type = cleaned_data.get('type')
if type == 'performance':
repertoire = cleaned_data.get('repertoire')
performer = cleaned_data.get('performer')
if not repertoire:
self.add_error('repertoire', _("This field is required"))
if not performer:
self.add_error('performer', _("This field is required"))
return cleaned_data
The docs for form validation are here; https://docs.djangoproject.com/en/3.1/ref/forms/validation/
I want to create a custom form validation in Django forms. I am able to do it normal Django forms but unable to do it in model forms.
my Django form code is
class Post_Article(forms.Form):
title = forms.CharField(label = 'Title',max_length = 100)
abstract = forms.CharField(widget = forms.Textarea, max_length = 300)
body = forms.CharField(widget = forms.Textarea)
image = forms.ImageField(required = False)
hash_tags = forms.CharField(max_length = 50,required = False)
def no_of_hash_tags(self):
cleaned_data = super().no_of_hash_tags()
tags = cleaned_data.get('hash_tags')
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValiadationError('Maximum 5 tags are allowed')
the Django model is
class PostsArticle(models.Model):
title = models.CharField(max_length=255)
pub_date = models.DateTimeField(default= timezone.now)
abstract = models.TextField()
body = models.TextField()
image = models.ImageField(upload_to=('images/'),blank=True)
user = models.ForeignKey(User , on_delete = models.CASCADE)
hash_tags = models.CharField(max_length = 50,blank= True)
def _str_(self):
return self.title
def get_absolute_url(self):
return reverse('home')
def summary(self):
return self.absract[:200]
def pub_date_pretty(self):
return self.pub_date.strftime('%b %e %Y')
def link_tags(self):
cleaned_data = super().link_tags
tags = cleaned_data.get['hash_tags']
for tag in tags:
hashing(tag,"PostsArticle")
After some discussion on stack overflow I updates my Django forms to
class Post_Article(forms.ModelForm):
title = forms.CharField(label = 'Title',max_length = 100)
abstract = forms.CharField(widget = forms.Textarea, max_length = 300)
body = forms.CharField(widget = forms.Textarea)
image = forms.ImageField(required = False)
hash_tags = forms.CharField(max_length = 50,required = False)
class Meta:
model = PostsArticle
fields=("title", "abstract", "body", "image", "hash_tags")
def clean(self)
:
cleaned_data=super(Post_Article, self).clean()
tags = cleaned_data.get("hash_tags")
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValidationError('Maximum 5 tags are allowed')
return cleaned_data
Now I am unable to get how can I use it with my current class used in views.py
class FeedUpdateView(LoginRequiredMixin, UserPassesTestMixin , UpdateView):
model = FeedPosts
fields= ['body', 'image']
template_name= 'post/edit_Feed.html'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
Posts = self.get_object()
if self.request.user == Posts.user:
return True
return False
I want to use my Django forms code instead of creating view from my model directly. I want to do it because I want to have some custom validation of a field as given in my forms code
kindly help how can I add form validation to my model
Cleaning a specific field attribute, you would have to call clean_<field_name>.
class Post_ArticleForm(ModelForm):
class Meta:
model = PostsArticle
fields = ['abstract', 'title', 'body', 'image', 'hash_tags']
def clean_hash_tags(self):
cleaned_data = super().clean_hash_tags()
tags = self.cleaned_data.get('hash_tags')
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValiadationError('Maximum 5 tags are allowed')
return cleaned_data
You need to override clean method for your ModelForm.
Example:
class Post_Article(forms.ModelForm):
...
hash_tags = forms.CharField(max_length = 50,required = False)
...
class Meta:
model = PostsArticle
fields=("title", "abstract", "body", "image", "hash_tags",)
def clean(self):
cleaned_data=super(Post_Article, self).clean()
tags = cleaned_data.get("hash_tags")
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValidationError('Maximum 5 tags are allowed')
return cleaned_data
the clean funtion is not getting invoked
Django forms is
class Post_Article(forms.ModelForm):
title = forms.CharField(label = 'Title',max_length = 100)
abstract = forms.CharField(widget = forms.Textarea, max_length = 300)
body = forms.CharField(widget = forms.Textarea)
image = forms.ImageField(required = False)
hash_tags = forms.CharField(max_length = 50,required = False)
class Meta:
model = PostsArticle
fields=("title", "abstract", "body", "image", "hash_tags")
def clean(self):
print(hello)
cleaned_data=super(Post_Article, self).clean()
tags = cleaned_data.get("hash_tags")
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValidationError('Maximum 5 tags are allowed')
return cleaned_data
the clean funtion is not getting invoked
the formview for the same is
class PostCreateView(LoginRequiredMixin,FormView):
form_class = Post_Article
template_name= 'post/post.html'
success_url = '/'
def form_valid(self, form):
form.instance.user = self.request.user
print(form.instance.user)
return super().form_valid(form)
the formview is in the views.py
I am creating a Health App that will take the Identity, Symptom, Disease and Treatment of the patient.
I have created models: Identity, Symptom, Disease, Treatment.
I am using form.ModelForm so that I can save the data to the db i.e. sqlite3.
I have created class based views that will handle forms, take field values, sanitize the data, and render the required form and values.
Problem: Each time I attempt to save values for the Symptom form it
seems to save it, and redirect to a new form but I am not seeing it in
the Admin Backend.
Code:
Model document
from django.db import models
from django.utils import timezone
import datetime
class Identity(models.Model):
NIS =models.CharField(max_length = 200, primary_key = True)
timestamp = models.DateTimeField(auto_now = True)
first_name = models.CharField(max_length = 80, null = True)
last_name = models.CharField(max_length = 80, null = True )
contact = models.CharField(max_length = 15, null = True)
location = models.CharField(max_length = 100, blank = True)
birthday= models.DateField(auto_now = False, auto_now_add = False, blank = True, null = True)
def __str__(self):
return '%s, %s' % (self.first_name ,self.last_name)
class Symptom(models.Model):
condition_name = models.CharField(max_length = 80, default = '')
description = models.TextField(max_length = 1000, default = '')
def __str__(self):
return self.condition_name
class Disease(models.Model):
disease_name = models.CharField(max_length = 80, default = '')
description = models.TextField(max_length = 1000, default = '')
def __str__(self):
return self.disease_name
class Treatment(models.Model):
term = models.CharField(max_length = 80, default = '')
treatment = models.TextField()
patient = models.ManyToManyField(Identity, through = 'Consultation')
date_done = models.DateField(auto_now = False, auto_now_add = False, blank = True, null = True)
def __str__(self):
return self.Term
class Consultation(models.Model):
patient_identity = models.ForeignKey(Identity)
patient_condition = models.ForeignKey(Symptom)
patient_disease = models.ForeignKey(Disease)
patient_treatment = models.ForeignKey(Treatment)
date_seen = models.DateField(auto_now = False, auto_now_add = False, blank = True, null = True)
def __str__(self):
return '%s' %(self.patient_identity)
Views document
from django.shortcuts import render, redirect
from django.views.generic import CreateView, ListView, DetailView, FormView, TemplateView
from patient.models import Identity, Symptom, Treatment, Disease, Consultation
from patient.forms import IdentityScript, SymptomScript
class Identity_view(CreateView):
model = Identity
template_name = 'patient/script.html'
def get(self, request):
form = IdentityScript()
script = Identity.objects.all()
var = {'form':form, 'script':script}
return render(request, self.template_name, var)
def post(self, request):
form = IdentityScript(request.POST)
being = None
if form.is_valid():
NIS = form.save(commit = False)
NIS.user = request.user
NIS.save()
being = form.cleaned_data['first_name']
form = IdentityScript()
return redirect('script:script')
var = {'form':form, 'being':being}
return render(request, self.template_name, var)
class Identity_list_view(ListView):
model = Identity
template_name = 'patient/Identity_list.html'
def get(self, request):
form = IdentityScript()
script = Identity.objects.all().order_by('-Timestamp')
var = {'form':form, 'script':script}
return render(request, self.template_name, var)
class Medical_document(CreateView):
model = Symptom
template_name = 'patient/medical_document.html'
def get(self, request, pk):
form = SymptomScript()
expression = Symptom.objects.all()
var = {'form':form, 'expression':expression, 'pk':pk}
return render(request, self.template_name, var)
def post(self, request, pk):
form = SymptomScript()
state = None
if form.is_valid():
manuscript = form.save(commit = False)
manuscript.user = request.user
state = form.cleaned_data['description']
manuscript.save()
patient = Identity.objects.get(pk=pk)
form = SymptomScript()
redirect('script:script')
else:
print(form)
var = {'form': form, 'state':state, 'pk':pk}
return render(request, self.template_name, var)
Forms document
from django import forms
from patient.models import Identity, Symptom, Disease
class IdentityScript(forms.ModelForm):
NIS = forms.CharField(
widget = forms.TextInput(
attrs = {
'placeholder': 'Enter NIS',
'class' : 'form-control'
}
)
)
first_name = forms.CharField(
widget = forms.TextInput(
attrs = {
'placeholder': 'Enter First Name',
'class' : 'form-control'
}
)
)
last_name = forms.CharField(
widget = forms.TextInput(
attrs = {
'placeholder': 'Enter Last Name',
'class' : 'form-control'
}
)
)
contact = forms.CharField(
widget = forms.TextInput(
attrs = {
'placeholder':'Enter Contact',
'class':'form-control'
}
)
)
born = forms.DateField(
widget = forms.TextInput(
attrs = {
'placeholder' : 'Enter Birth',
'class':'form-control'
}
)
)
location = forms.CharField(
widget = forms.TextInput(
attrs = {
'placeholder':'Enter location',
'class':'form-control'
}
)
)
class Meta:
model = Identity
fields = ('NIS', 'first_name', 'last_name', 'birthday', 'location', 'contact', )
class DiseaseScript(forms.ModelForm):
disease_name = forms.CharField(
widget = forms.TextInput(
attrs = {
'placeholder': 'Enter Disease Name',
'class' : 'form-control'
}
)
)
description = forms.CharField(
widget = forms.TextInput(
attrs = {
'placeholder': 'Enter description',
'class' : 'form-control'
}
)
)
class Meta:
model = Disease
fields = ('disease_name', 'description')
# Create SymptomScript form
class SymptomScript(forms.ModelForm):
condition_name = forms.CharField(
widget = forms.TextInput(
attrs = {
'placeholder': 'Enter Condition Name',
'class' : 'form-control'
}
)
)
description = forms.CharField(
widget = forms.Textarea(
attrs = {
'placeholder': 'Enter Description',
'class' : 'form-control'
}
)
)
class Meta:
model = Symptom
fields = ('condition_name', 'description')
My Models are look like .....
Student(models.Model):
name = models.CharField(max_length = 60, blank = False)
r_no = models.CharField(max_length = 60, blank = False)
created_date = models.DateTimeField(null = False, blank = False, default = datetime.datetime.now())
StudentPotential(models.Model):
aka_name = models.CharField(max_length = 60, blank = True)
-----
-----
StudentCorrespondence(models.Model):
student = models.ForeignKey('Student', related_name = "Student_FK")
student_p = models.ForeignKey('Student', related_name = "Student_FK")
emailed_date = models.DateTimeField(null = True, blank = True)
phoned_date = models.DateTimeField(null = True, blank = True)
My Form in form.py
class StudentPotentialForm (forms.ModelForm):
class Meta:
model = StudentPotential
class StudentCorrespondenceForm(forms.ModelForm):
class Meta:
model = StudentCorrespondence
exclude = ('student', 'student_p')
Finally My view.py
def add_student_company_potential(request, student_id):
from cdradmin.forms import StudentPotentialForm, StudentCorrespondenceForm
if request.method == 'POST':
### HOW TO SAVE THE two from for the student have its it 'student_id' ####
else:
StudentPotentialForm = StudentPotentialForm()
StudentCorrespondenceForm = StudentCorrespondenceForm()
context = {'StudentCorrespondenceForm':StudentCorrespondenceForm, "StudentPotentialForm":StudentPotentialForm}
return render_to_response('cdradmin/studentform.html', context, context_instance = RequestContext(request))
Once the data is post to the view, How can i able to save this data for the student has his/her id is 'student_id'
You can try this
if request.method == 'POST':
spf = StudentPotentialForm(request.POST)
if spf.is_valid():
osp = spf.save()
else :
#raise error
student = Student.objects.get(id=student_id)
scf = StudentCorrespondenceForm(request.POST)
if scf.is_valid():
osc = scf.save(commit=False)
osc.student = student
osc.student_p = osp
osc.save()
else:
# raise error.
forms.py
class UserProfileForm(forms.ModelForm):
phone = forms.CharField(max_length = 15,widget = forms.TextInput(attrs = {'placeholder':'Enter mobile no. ','class':''}))
profession = forms.CharField(max_length= 50,widget = forms.Select(choices = PROFESSION_CHOICES,attrs = {'class':''}))
#email = forms.EmailField(label='Email address',max_length = 75,widget = forms.TextInput(attrs={'placeholder':'Email address.','class':''}))
sex = forms.CharField(max_length = 20,label="I am :",widget=forms.Select(choices=SEX_CHOICES,attrs = {'class':''}))
first_name = forms.CharField(max_length = 50,widget = forms.TextInput(attrs={'placeholder':'Please enter your real name.','class':''}))
last_name = forms.CharField(max_length = 50,widget = forms.TextInput(attrs={'placeholder':'Enter last name.','class':''}))
location = forms.CharField(max_length = 50,widget = forms.TextInput(attrs={'placeholder':'Enter your current location','class':''}))
def clean_first_name(self):
first_name = self.cleaned_data['first_name']
if first_name == '':
raise forms.ValidationError("This field is required.")
return first_name
def save(self,*args,**kw):
self.instance.first_name = self.cleaned_data.get("first_name")
self.instance.last_name = self.cleaned_data.get("last_name")
self.instance.sex = self.cleaned_data.get("sex")
self.instance.location = self.cleaned_data.get("location")
self.instance.profession = self.cleaned_data.get("profession")
self.instance.phone = self.cleaned_data.get("phone")
self.instance.save()
return self.instance
class Meta:
model = User
fields = ('username','first_name','last_name','phone','sex','profession','location')
views.py
def profile(request,nav="profile",template="profile.html",context = {},extra_context = None):
if request.POST:
if 'profileFormSubmit' in request.POST:
pform = UserProfileForm(request.POST,instance = request.user)
if pform.is_valid():
try:
user = pform.save()
return redirect(profile,nav="profile")
except RuntimeError as e:
return HttpResponse(e)
error
The User could not be changed because the data didn't validate.
line
user = super(UserProfileForm,self).save(*args,**kw)
doubt
what changes am i supposed to make to get rid of this error
how am i supposed to change the , i have tried removing all the clean_field form methods , but still getting the same error , please help , thanks in advance.
You are calling save on your form before you clean. And you are calling save twice. Once at the start of the form save. And once at the end.
pform.is_valid() returns a boolean that you never check.
docs on modelforms
The form wasn't validating because I was using 'username' in my meta class of the UserProfileForm, which wasn't supposed to be there.