Django says "Note that if the form hasn’t been validated, calling save() will do so by checking form.errors. A ValueError will be raised if the data in the form doesn’t validate – i.e., if form.errors evaluates to True."
What I am not able to clear out is
Will the validation be run when I call the save on the ModelForm?
And if I have validated the form data using form.is_valid() method than will the save() method do the validation again.(I am asking this as some validation requires I do a database query for Foreign Key validation as it has some restriction)
I am asking this question as if the first one is true than I think it would be a good idea to not to validation at all and rather just call the save method, letting it call the validation method and just catching it.
First question - yes. As the docs say, calling save() accesses form.errors, which triggers validation if the form has not yet been validated.
Second question - no, the validation will not be run again. Once the form has been validated, whether by calling is_valid() or by calling .save(), form.errors is populated and can be read from without re-running validation.
With either approach, validation will be run exactly once.
Related
In short: I have a model with several fields, and on this model is a foreign-key field connecting it to to a User instance. Then, I have a model-form(1) that generates HTML for this model's fields, and that with a custom ModelChoiceField-instance that presents UserProfile-instances instead of User-instances. To validate the submitted information, I have a form (regular form) that validates that a UserProfile-instance was submitted. If it was, I update request.POST (through a copy of it), and validate against a second model-form(2) that exactly mirrors the underlying model.
This all means that I first have to pass a request.POST with a lot of un-validated information into a form that only validates part of it, then updated a copy of a partially validated request.POST, edit it, and then finally validate it again.
Is all of this safe? Is it considered bad practice/unsafe to pass a request.POST with a lot of information into a form that only validates one part of it? Additionally, is it safe to make a copy of a request.POST that is only partially validated - and then update it?
To what degree can you work with objects containing unsafe information, such as request.POST, without it becoming a problem?
Thank you!
I had the following code working in Django 1.5:
if formset.is_valid():
formset.save()
The forms inside the formset are performing a check inside clean() to make sure that certain required fields are entered (only known at runtime). This means that although a user might not enter any values the validation would still run and ask for data entry if required.
With Django 1.6 this behaviour does not apply anymore. If there was no change then the form's clean() method does not get called anymore when calling formset.is_valid().
I could not find anything in the changelogs that would explain this new behvaiour. Is there a flag on formset.is_valid() to force the validation even if no changes were made?
It seems as if the validation was skipped since the formset changed the form's edit_permitted attribute.
The following change fixed the issue I had:
# Was required to disable shortcut for validation when
# no data was entered
for form in formset:
form.empty_permitted = False
We are using some complex form workflow where we want to have a kind of Ajax prevalidation verifications all the time before final submission (and validation). So we are making an Ajax request to the server and validating the form, but not saving the results. If there are errors, we display them to the user.
But the issue is with required fields which all get marked as missing values, when they are empty (because the user has not yet finalized the form's content). So my question is, how can we make a validation run on only those fields which are not empty? For final submission we will validate all fields and catch missing fields. But for this partial validation we would like to have only filled fields validated.
One approach would be to iterate through the form fields setting required=False prior to validation. In your ajax view, something like this should work:
for field in myform.fields.itervalues():
field.required = False
json_result = json.dumps({'form_valid': myform.is_valid()})
Can anyone explain this? It's really unintuitive that a form validation method would update the related model. I understand it doesn't commit to the database, but why even modify the model in memory? Why not do it with form.save()?
I believe the reason is this:
The first time you call is_valid() or
access the errors attribute of a
ModelForm has always triggered form
validation, but as of Django 1.2, it
will also trigger model validation.
This has the side-effect of cleaning
the model you pass to the ModelForm
constructor. For instance, calling
is_valid() on your form will convert
any date fields on your model to
actual date objects.
From here. Logically, this does actually make sense. Suppose I have a model like this:
class SomeModel(models.Model):
Somefield = models.CharField(unique=True)
Then as far as the modelform is concerned, validating the field TextInputField would work for any value. However, from the model's perspective, not any value will do - that value must be unique.
The validation mechanisms are described here. Basically, calling full_clean on a model causes that model to check its own fields as per the OO paradigm. So for this reason, the in memory image of the model can be updated and validating it will check it can actually be written to the database.
Thus it makes sense, because your guard:
if form.is_valid():
Really ought to ensure that:
form.save()
Can actually happen.
Is it possible to add form errors (not a field specific errors) to a form that is already validated (form.is_valid() is already called and the result is True)?
I have additional validation logic (with database requests) which I prefer to execute after standard form validation is passed, but it will be better to associate new errors with form
Or maybe I have to call this additional validation within clear() form function?
Try to check it in the clean method of the form after all, but check existing errors before.
Like that..
clean(self):
...
...
if not self._errors:
# your extra check
If this is validation based on database requests, then it shound as model validation.