Since django
1.2 it is able to write validation code on model. When we work with modelforms, instance.full_clean() is called on form validation. But this code is not execute on save() method:
Note that full_clean() will not be called automatically when you call your model’s save() method, nor as a result of ModelForm validation.
For this reason, I alltimes call clean() model method before save model. I invoke this call trhough pre_save signal.
For more business rules issolation, I write all them in a separate python module: rules.py.
This is models.py ---------------------------------------------------------------
from django.db import models
class Issue(models.Model):
....
| def clean(self): |
| rules.Issue_clean(self) |
|
| from issues import rules |
| rules.connect() |
This is rules.py ---------------------------------------------------------------
from issues.models import Issue
def connect():
|
| from django.db.models.signals import post_save, pre_save, pre_delete |
| #issues |
| pre_delete.connect(Issue_pre_delete, sender= Incidencia) |
| pre_save.connect(Issue_pre_save, sender = Incidencia ) |
| post_save.connect(Issue_post_save, sender = Incidencia ) |
| def Incidencia_clean( instance ): |
| import datetime as dt |
| |
errors = {}
|
| #dia i hora sempre informats |
| if not instance.dia_incidencia: |
errors.setdefault('dia_incidencia',[]).append(u'Falten Dades: Cal dia i franja')
|
| |
| #dia i hora sempre informats |
| if not instance.franja_incidencia: |
| errors.setdefault('franja_incidencia',[]).append(u'Falten Dades: Cal dia i franja') |
| |
| #Només es poden posar incidències més ennlà de 7 dies |
| if instance.dia_incidencia < ( dt.date.today() + dt.timedelta( days = -7) ): |
| errors.setdefault('dia_incidencia 1',[]).append(u'''No es poden posar o modificar incidències amb més d' una setmana)''') |
| |
| #No incidències al futur. |
| if instance.getDate() > datetime.now(): |
| errors.setdefault('dia_incidencia 2',[]).append(u'''Encara no pots posar incidències en aquesta classe. Encara no s'ha realitzat.''') |
| |
#No incidencies alumne que és baixa:
|
| if instance.alumne.data_baixa is not None and instance.alumne.data_baixa < instance.dia_incidencia: |
| errors.setdefault('dia_incidencia 3',[]).append(u'''L'alumne estava de baixa en aquesta data.''') |
| |
| if len( errors ) > 0: |
| raise ValidationError(errors) |
| def Issue_pre_save(sender, instance, **kwargs): |
|
| instance.clean() |
In order to show errors on form, you should include this on form template:
| {% if form.non_field_errors %} |
| {% for error in form.non_field_errors %} |
{{error}}
|
| {% endfor %} |
|
{% endif %}
The reason is that model validation erros ara binded to non_field_errors error dictionary entry. |
When you save or delete a model out of a form:
try:
issue.delete()
except ValidationError, e:
import itertools
errors = list( itertools.chain( *e.message_dict.values() ) )
To add errors to a form dictionary on no modelforms:
try:
issue.clean()
except ValidationError, e:
form._errors = {}
for _, v in e.message_dict.items():
form._errors.setdefault(NON_FIELD_ERRORS, []).extend( v )
You can see samples on ghap project source code.
Here some samples: