web-dev-qa-db-fra.com

Déclenche une erreur de validation dans la méthode de sauvegarde d'un modèle dans Django

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.

55
Bastian

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".

51
Alasdair

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  )
25
dani herrera

assurez-vous d'importer également ValidationError

from Django.core.exceptions import ValidationError
1
Brendan
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)
0
Asif Akhtar

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)
0
megajoe