Je ne sais pas comment soulever correctement une erreur de validation dans la méthode de sauvegarde d'un modèle et renvoyer un message clair à l'utilisateur.
Fondamentalement, je veux savoir comment chaque partie du "si" doit se terminer, celle où je veux soulever l'erreur et celle où elle enregistre réellement:
def save(self, *args, **kwargs):
if not good_enough_to_be_saved:
raise ValidationError
else:
super(Model, self).save(*args, **kwargs)
Ensuite, je veux savoir quoi faire pour envoyer une erreur de validation qui indique exactement à l'utilisateur ce qui ne va pas, tout comme celui Django renvoie automatiquement si, par exemple, une valeur n'est pas unique. J'utilise a (ModelForm) et tout régler à partir du modèle.
La plupart des vues Django, par exemple, l'administrateur Django ne sera pas en mesure de gérer une erreur de validation dans la méthode de sauvegarde, de sorte que vos utilisateurs recevront 500 erreurs).
Vous devez faire la validation sur le formulaire modèle ou sur le modèle, et y élever ValidationError
. Appelez ensuite save()
uniquement si les données du formulaire du modèle sont "suffisamment bonnes pour être enregistrées".
Bastian, je vous explique mon code gabarit, j'espère que ça vous aide:
Depuis Django 1.2 il est capable d'écrire du code de validation sur le modèle . Lorsque nous travaillons avec des formulaires modèles, instance.full_clean () est appelée lors de la validation du formulaire.
Dans chaque modèle, j'écrase la méthode clean()
avec une fonction personnalisée (cette méthode est automatiquement appelée depuis full_clean () lors de la validation du formulaire):
from Django.db import models
class Issue(models.Model):
....
def clean(self):
rules.Issue_clean(self) #<-- custom function invocation
from issues import rules
rules.connect()
Ensuite, dans le fichier rules.py
, J'écris des règles commerciales. Je connecte également pre_save()
à ma fonction personnalisée pour éviter d'enregistrer un modèle avec un mauvais état:
from issues.models import Issue
def connect():
from Django.db.models.signals import post_save, pre_save, pre_delete
#issues
pre_save.connect(Issue_pre_save, sender = Incidencia )
post_save.connect(Issue_post_save, sender = Incidencia )
pre_delete.connect(Issue_pre_delete, sender= Incidencia)
def Incidencia_clean( instance ): #<-- custom function
import datetime as dt
errors = {}
#dia i hora sempre informats
if not instance.dia_incidencia: #<-- business rules
errors.setdefault('dia_incidencia',[]).append(u'Data missing: ...')
#dia i hora sempre informats
if not instance.franja_incidencia:
errors.setdefault('franja_incidencia',[]).append(u'Falten Dades: ...')
#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'''blah blah error desc)''')
#No incidències al futur.
if instance.getDate() > datetime.now():
errors.setdefault('dia_incidencia 2',[]).append(u'''Encara no pots ....''')
...
if len( errors ) > 0:
raise ValidationError(errors) #<-- raising errors
def Issue_pre_save(sender, instance, **kwargs):
instance.clean() #<-- custom function invocation
Ensuite, modelform appelle la méthode propre du modèle et ma fonction custon vérifie l'état correct ou génère une erreur gérée par le formulaire modèle.
Afin d'afficher les erreurs sur le formulaire, vous devez l'inclure dans le modèle de formulaire:
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
{{error}}
{% endfor %}
{% endif %}
La raison en est que les erreurs de validation de modèle sont liées à une entrée de dictionnaire d'erreurs non_field_errors.
Lorsque vous enregistrez ou supprimez un modèle d'un formulaire, vous devez vous rappeler qu'une erreur peut se produire:
try:
issue.delete()
except ValidationError, e:
import itertools
errors = list( itertools.chain( *e.message_dict.values() ) )
En outre, vous pouvez ajouter des erreurs à un dictionnaire de formulaires sur aucun formulaire de modèle:
try:
#provoco els errors per mostrar-los igualment al formulari.
issue.clean()
except ValidationError, e:
form._errors = {}
for _, v in e.message_dict.items():
form._errors.setdefault(NON_FIELD_ERRORS, []).extend( v )
N'oubliez pas que ce code n'est pas exécuté sur la méthode save (): notez que full_clean () ne sera pas appelé automatiquement lorsque vous appelez la méthode save () de votre modèle, ni à la suite de la validation ModelForm. Ensuite, vous pouvez ajouter des erreurs à un dictionnaire de formulaires sur aucun modelforms :
try:
#provoco els errors per mostrar-los igualment al formulari.
issue.clean()
except ValidationError, e:
form._errors = {}
for _, v in e.message_dict.items():
form._errors.setdefault(NON_FIELD_ERRORS, []).extend( v )
assurez-vous d'importer également ValidationError
from Django.core.exceptions import ValidationError
def clean(self):
raise ValidationError("Validation Error")
def save(self, *args, **kwargs):
if some condition:
#do something here
else:
self.full_clean()
super(ClassName, self).save(*args, **kwargs)
Je pense que c'est une façon plus claire de le faire pour Django 1.2+
Dans les formulaires, il sera relevé comme non_field_error, dans d'autres cas, comme DRF, vous devez vérifier ce manuel de cas, car ce sera une erreur de 500.
class BaseModelExt(models.Model):
is_cleaned = False
def clean(self):
# check validation rules here
self.is_cleaned = True
def save(self, *args, **kwargs):
if not self.is_cleaned:
self.clean()
super().save(*args, **kwargs)