Some of Django's choices on how to handle data integrity are wrong, or at the very least, unexpected to the uninitiated developers. I'm not here to pass judgement; like many people, I'd just like to get back to doing real work. Some notes on how to stay safe in Django:
- Django now has both Form validations and Model validations
- Django used to only have Form validations
- Form’s
is_valid()
performs model validation automatically full_clean()
is never actually called by Django (see ticket #13100)
- Stay DRY
- Read http://schneck.cc/node/41
- Put model validation only in
clean()
to avoid confusion - Never overwrite
full_clean()
- Use model validation whenever possible.
- Before you save an object, apply
full_clean()
on it.
Always run model validation before saving a model instance
# http://djangosnippets.org/snippets/2319/
from django.db.models.signals import pre_save
def validate_model(sender, **kwargs):
if 'raw' in kwargs and not kwargs['raw']:
kwargs['instance'].full_clean()
pre_save.connect(validate_model, dispatch_uid='validate_models')
# http://djangosnippets.org/snippets/337/
from django.forms.utils import ErrorList
def clean(self):
cleaned = self.cleaned_data
errors = False
#
# Validate stuff here!
#
if there_are_errors_for_field1:
self._errors['field1'] = self._errors.get('field1', ErrorList())
self._errors['field1'].append(_("Field 1 is invalid"))
errors = True
if there_are_errors_for_field2:
self._errors['field2'] = self._errors.get('field2', ErrorList())
self._errors['field2'].append(_("Field 2 is invalid"))
errors = True
non_field_errors = []
if there_are_other_errors:
non_field_errors.append(_("Non field error"))
errors = True
if errors:
raise form.ValidationError(non_field_errors)
return cleaned
# http://stackoverflow.com/questions/6892162/django-1-3-createview-modelform-unique-together-validation-with-one-field-exclud
class SubscriberForm(ModelForm):
class Meta:
model = Subscriber
exclude = ('user')
class SubscriberCreateView(AuthCreateView):
model = Subscriber
form_class = SubscriberForm
template_name = "forms/app.html"
success_url = "/app/subscribers/"
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
try:
self.object.full_clean()
except ValidationError:
from django.forms.util import ErrorList
form._errors["email"] = ErrorList([u"You already have an email with that name."])
return super(SubscriberCreateView, self).form_invalid(form)
return super(SubscriberCreateView, self).form_valid(form)
# http://stackoverflow.com/questions/1057252/django-how-do-i-access-the-request-object-or-any-other-variable-in-a-forms-clea
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj, **kwargs)
def form_wrapper(*args, **kwargs):
return ModelForm(request=request, *args, **kwargs)
return form_wrapper
class MyCustomForm(forms.ModelForm):
def __init__(self, request=None, *args, **kwargs):
self.request = request
super(MyCustomForm, self).__init__(*args, **kwargs)
You can then access the request object from any method of ModelForm with self.request
.