2012-01-07 75 views
38

我不確定如何在模型的保存方法中正確引發驗證錯誤並向用戶發送清晰的消息。在Django的模型保存方法中引發驗證錯誤

基本上我想知道如何的每一個部分的「如果」應該結束,一,我想引發錯誤 和一個地方,它實際上節省了:

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

然後,我想知道怎麼做才能發送驗證錯誤,該錯誤恰好向用戶說明了什麼是錯誤的,就像Django自動返回一個錯誤,例如一個值不是唯一的。 我正在使用(ModelForm)並調整模型中的所有內容。

回答

32

大多數Django的意見,例如Django管理員將無法處理保存方法中的驗證錯誤,因此您的用戶將得到500個錯誤。

您應該在模型表單或模型上進行驗證,並在那裏提出ValidationError。只有在模型表格數據「足夠保存」的情況下,才能撥打save()

+0

你說得對,我將我的驗證進入形式,它更容易。我只是喜歡在模型中擁有一切的想法。 – Bastian 2012-01-08 07:02:40

+8

@bastian,我也喜歡在模型中擁有一切。編寫新表單時很容易忘記業務規則,但如果業務規則在模型中則不會。出於這個原因,我已經將驗證從表單轉移到了模型中,正如我在我的文章中所解釋的。我很樂意瞭解新方法,如果它存在,可以用更優雅的方式來實現。無論如何我都避免在表單上寫驗證碼。 – danihp 2012-01-08 14:31:06

+6

通過使用驗證器或者寫一個'clean()'方法來驗證你的模型是很好的。我只是說'save()'方法不是正確的地方。查看關於[驗證對象]的文檔(https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects)。 – Alasdair 2012-01-08 17:04:42

22

巴斯蒂安,我向你解釋我的代碼模板,我希望可以幫助到你:

由於django 1.2 it is able to write validation code on model。當我們使用模型時,instance.full_clean()在表單驗證上被調用。

在每個模型我覆蓋clean()方法使用自定義功能(該方法將自動從full_clean上的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() 

然後在rules.py文件I寫經營業務規則。此外,我連pre_save()到我的自定義功能,防止保存錯誤狀態的模型:

從issues.models進口問題

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 

然後,調用的ModelForm模型的清潔方法和右狀態我custon功能檢查或引發由模型形式處理的錯誤。

爲了顯示對形式的錯誤,你應該包括這個對錶單模板:

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

的原因是綁定到non_field_errors錯誤辭典條目,模型驗證錯誤回報ARA。

當您保存或刪除模型表單,你應該記住,一個錯誤可能提出:

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 ) 

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

此外,您還可以在沒有modelforms到表單字典添加錯誤

請記住,此代碼不在save()方法上執行:請注意,調用模型的save()方法時不會自動調用full_clean(),也不會因ModelForm驗證而調用該方法。然後,你可以到一個表單字典加上沒有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

Moltesgràcies爲您冗長的解釋。我正在自動尋找一些東西,Djangoish。你的例子可能會讓我對其他情況感興趣,但我現在正在寫的一個只是一個線路驗證,所以我不會在這裏實現整個事情。 – Bastian 2012-01-08 07:01:46

+3

不客氣。不要忘記有一天會訪問加泰羅尼亞:) – danihp 2012-01-08 10:07:42

+7

我住在巴塞羅那:) – Bastian 2012-01-08 15:15:45

1

一定要導入ValidationError以及

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

發佈代碼是不夠的,你應該提供一些解釋。 – Ivan 2017-12-01 11:58:54

+0

你可以在保存函數中調用full_clean()方法,這在Django == 1.11中工作正常,我不確定舊版本。 – 2017-12-01 12:35:03

+0

將此信息添加到您的答案以改進它。 – Ivan 2017-12-01 12:37:40

相關問題