2012-01-07 22 views
38

No estoy seguro de cómo plantear correctamente un error de validación en el método de guardado de un modelo y devolver un mensaje claro al usuario.Elevar un error de validación en el método de guardado de un modelo en Django

Básicamente quiero saber cómo cada parte del "si" debe terminar, la que yo quiero plantear el error y aquel en el que realmente ahorra:

def save(self, *args, **kwargs): 
    if not good_enough_to_be_saved: 
     raise ValidationError 
    else: 
     super(Model, self).save(*args, **kwargs) 

Entonces quiero saber qué hacer para enviar un error de validación que indique exactamente al usuario cuál es el error, como el que Django devuelve automáticamente si, por ejemplo, un valor no es exclusivo. Estoy usando un (ModelForm) y ajusto todo desde el modelo.

Respuesta

32

La mayoría de las vistas de Django p. el administrador de Django no podrá manejar un error de validación en el método de guardar, por lo que los usuarios recibirán 500 errores.

Debe hacer la validación en el formulario del modelo o en el modelo, y plantear allí ValidationError. Luego llame al save() solo si los datos del formulario modelo son 'lo suficientemente buenos para guardar'.

+0

Tienes razón voy a mover mi validación en la forma, es mucho más fácil. Me gustó la idea de tener todo en el modelo. – Bastian

+8

@bastian, también me gusta tener todo en el modelo. Es fácil olvidarse de una regla comercial cuando escribe un formulario nuevo, pero no si las reglas comerciales están en el modelo. Por este motivo, he trasladado las validaciones de los formularios al modelo, como explico en mi publicación. Estoy abierto a aprender sobre nuevos métodos para hacer esto de una manera más elegante si existe. En cualquier caso evito escribir código de validación en formularios. – danihp

+6

Está bien poner validación en su modelo utilizando validadores o escribiendo un método 'clean()'. Todo lo que estaba diciendo es que el método 'save()' no es el lugar correcto. Eche un vistazo a los documentos sobre [validación de objetos] (https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects). – Alasdair

22

Bastian, te explico mi código de plantillas, espero que ayuda a que:

Desde django 1.2 it is able to write validation code on model. Cuando trabajamos con modelos, se invoca instance.full_clean() en la validación del formulario.

En cada modelo I sobrescribir clean() método con una función personalizada (este método es llamado automáticamente de full_clean() en la validación ModelForm):

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() 

Luego, en rules.py archivo que he escribir reglas de negocios. También me conecto a mi pre_save() función personalizada para evitar guardar un modelo con un estado incorrecto:

de Emisión issues.models importación

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 

Entonces, ModelForm llama al método limpio de modelo y mi control de funcionamiento del custon para un estado correcto o genera un error que se maneja por formulario modelo.

Con el fin de mostrar los errores de forma, debe incluir en esta plantilla de formulario:

{% if form.non_field_errors %} 
     {% for error in form.non_field_errors %} 
     {{error}} 
     {% endfor %} 
{% endif %} 

La razón es que los erros de validación del modelo ara binded a un error non_field_errors entrada de diccionario.

Al guardar o borrar un modelo de una forma que usted debe recordar que un error puede ser elevado:

try: 
    issue.delete() 
except ValidationError, e: 
    import itertools 
    errors = list(itertools.chain(*e.message_dict.values())) 

Además, se puede añadir errores a un diccionario formulario en ningún 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 ) 

Recuerde que este código no se ejecuta en el método save(): tenga en cuenta que full_clean() no se invocará automáticamente cuando llame al método save() de su modelo ni como resultado de la validación de ModelForm.A continuación, puede agregar errores a un diccionario en forma no 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 ) 
+1

Moltes gràcies para su larga explicación. Estaba buscando algo automático, Djangoish. Su ejemplo podría interesarme por otras situaciones, pero la que estoy escribiendo ahora es solo una validación de 1 línea, así que no implementaré todo aquí. – Bastian

+3

De nada. No olvides visitar Cataluña algún día :) – danihp

+7

Vivo en Barcelona :) – Bastian

1

asegúrese de importar el ValidationError así

from django.core.exceptions import ValidationError 
-1
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) 
+1

El código de publicación no es suficiente, deberías dar alguna explicación. – Ivan

+0

puede llamar al método full_clean() en la función de guardar, esto funciona bien en Django == 1.11, no estoy seguro acerca de la versión anterior. –

+0

Agregue esta información a su respuesta para mejorarlo. – Ivan

Cuestiones relacionadas