2012-01-07 12 views
38

Non sono sicuro di come generare correttamente un errore di convalida nel metodo di salvataggio di un modello e di inviare un messaggio chiaro all'utente.Aumentare un errore di convalida nel metodo di salvataggio di un modello in Django

Fondamentalmente voglio sapere come ogni parte del "se" dovrebbe terminare, quello in cui vorrei sollevare l'errore e quello in cui si salva effettivamente:

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

poi voglio sapere cosa fare per inviare un errore di convalida che dice esattamente all'utente che cosa non va, proprio come quello che Django restituisce automaticamente se per esempio un valore non è univoco. Sto usando un (ModelForm) e tune tutto dal modello.

risposta

32

La maggior parte delle visualizzazioni Django, ad es. l'amministratore di Django non sarà in grado di gestire un errore di convalida nel metodo di salvataggio, quindi gli utenti riceveranno 500 errori.

Si dovrebbe fare la convalida sul modulo del modello o sul modello e sollevare ValidationError lì. Quindi chiamare save() solo se i dati del modulo del modello sono "abbastanza buoni da salvare".

+0

Hai ragione mi trasferirò la mia convalida in la forma, è molto più facile. Mi è piaciuta l'idea di avere tutto nel modello. – Bastian

+8

@bastian, mi è piaciuto anche avere tutto nel modello. È facile dimenticare una regola aziendale quando si scrive un nuovo modulo, ma non se le regole aziendali sono nel modello. Per questo motivo ho spostato le convalide dai moduli al modello, come ho spiegato nel mio post. Sono aperto a conoscere nuovi metodi per farlo in un modo più elegante se esiste. In ogni caso evito di scrivere codice di convalida sui moduli. – danihp

+6

Va bene mettere la validazione nel tuo modello usando i validatori o scrivendo un metodo 'clean()'. Tutto quello che stavo dicendo è che il metodo 'save()' non è il posto giusto. Dai un'occhiata ai documenti su [validating objects] (https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects). – Alasdair

22

Bastian, spiego a voi il mio codice di template, spero che aiuta a voi:

Dal django 1.2 it is able to write validation code on model. Quando lavoriamo con modelforms, instance.full_clean() viene chiamato sulla convalida del modulo.

In ogni modello ho sovrascrivere clean() metodo con una funzione personalizzata (questo metodo viene chiamato automaticamente da full_clean() sulla convalida 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() 

Poi nel rules.py file scrivere regole di bussiness. Inoltre mi collego al mio pre_save() funzione personalizzata per prevenire salvare un modello con stato errato:

da issues.models importazione Problema

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 

Poi, ModelForm chiama metodo pulito del modello e il mio custon controllo del funzionamento di uno stato diritto o genera un errore gestito dal modulo del modello.

Al fine di mostrare gli errori di forma, si dovrebbe includere questo sul modello di modulo:

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

La ragione è che erros validazione del modello ara binded per errore non_field_errors voce di dizionario.

Quando si salva o si elimina un modello di una forma si dovrebbe ricordare che un errore può essere sollevato:

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

Inoltre, è possibile aggiungere gli errori a un dizionario modulo non 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 ) 

Ricordare che questo codice non viene eseguito sul metodo save(): si noti che full_clean() non verrà chiamato automaticamente quando si chiama il metodo save() del modello, né come risultato della convalida ModelForm.Quindi, è possibile aggiungere gli errori a un dizionario modulo a non 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 dispiace per la tua lunga spiegazione. Stavo cercando qualcosa di automatico, Djangoish. Il tuo esempio potrebbe interessarmi per altre situazioni, ma quello che sto scrivendo ora è solo una convalida di 1 linea, quindi non implementerò il tutto qui. – Bastian

+3

Prego. Non dimenticarti di visitare la Catalogna un giorno :) – danihp

+7

Vivo a Barcellona :) – Bastian

1

essere sicuri di importare il ValidationError così

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

Il codice di pubblicazione non è sufficiente, dovresti fornire qualche spiegazione. – Ivan

+0

puoi chiamare il metodo full_clean() nella funzione di salvataggio, questo funziona perfettamente con Django == 1.11, non sono sicuro della versione precedente. –

+0

Aggiungi questa informazione alla tua risposta per migliorarla. – Ivan

Problemi correlati