I have a Django form that will add an entry to a database with a unique constraint on one of the columns. If the submission happens to attempt creation of a duplicate, I get a django.db.utls.IntegrityError
stating I violated the unique constraint (thankfully).
When processing Django forms, there are a number of ways to validate:
- Override the form class'
clean
method - Override the form class'
clean_<field>
method
If the clear_<field>
method raises a django.forms.ValidationError
, the error message will be appended to a list in the _errors
dictionary under the field's name. When using the clean
method, errors should be manually inserted into the _errors
dict.
Now, the clean
and clean_<field>
methods don't sound like a nice place to put code that has side effects, and I fear that checking at this moment whether the value is unique does not guarantee I won't get IntegrityError
s. I would prefer to actually try and create the row in the database and signal a form error when a constraint is violated.
My main problem is that forms expose a public property errors
which is read-only. Therefore, I should, according to the docs, add a method in my form that does all the work, try to insert in the database and register an error when an IntegrityError
is raised. Because the action that processes the form after validation requires lots of other data, I don't want to put the code inside the form class itself.
Is there any other (documented or not) way to go about adding an entry in the errors
dict from outside the class, or should I simply access the _errors
"private" variable and be happy with that? I know this sounds like an OOP b开发者_如何转开发reach, but creating an extra method just to access this "private" variable does not seem to me like it shields anybody from anything.
Edit:
Seems like someone else already raised a similar question, but it seems the answers pointed to manual insertion into _errors
...
For now, a simple solution is the following:
try:
# Try to save model instance, which might throw `IntegrityError`.
# ...
except django.db.utils.IntegrityError:
# The form passed validation so it has no errors.
# Use the `setdefault` function just in case.
errors = django.forms.util.ErrorList()
errors = form._errors.setdefault(
django.forms.forms.NON_FIELD_ERRORS, errors)
errors.append('Sorry, this username is already in use.')
I think adding the method to the form is quite reasonable. The ModelForm class, which has a save() method which does the logic of saving the created instance to the database. If your form can inherit from ModelForm (or just add a save() method to your form), you'll still be well within "djangonian" standards.
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
精彩评论