2011-10-12 11 views
7

請幫助我瞭解我做出的以下選擇是慣用/好還是不好,如何改進。將Django模型驗證錯誤轉換爲表單的慣用方法

1)模型驗證了表單驗證
我更喜歡儘可能因爲它似乎更乾和基本方法來創建數據規則表單驗證使用新model validation。一個簡單的日曆入門車型的兩個例子:

  • 「開始必須在結束之前」
  • 「期間必須小於(最終開始)」

是它慣用/好把這些放在模型層面,這樣他們就不必被放入表單了?如果ModelForm是最好的答案,那麼在同一個表單中使用多個模型的情況呢?
(編輯:我不知道,多ModelForms實際上可以一起使用)

2)傳輸模型驗證一個表單(未的ModelForm)
(編輯:原來重塑在我的情況下,模型驗證和表單驗證之間不需要管道連接,下面的解決方案顯示了原因)
假設我們有任何模型驗證錯誤可以直接傳輸並直接顯示給用戶(即忽略翻譯模型驗證錯誤到用戶友好的表單驗證錯誤)。

這是我想出了做一個工作方式(在同一個地方,沒有輔助功能):

view_with_a_form: 
... 
if form.is_valid(): 
    instance = ... 
    ... 
    #save() is overridden to do full_clean with optional exclusions 
    try: instance.save() 
    except ValidationError e: 
     nfe= e.message_dict[NON_FIELD_ERRORS] 
     #this is one big question mark: 
     instance._errors['__all__'] = ErrorList(nfe) 
#this is the other big question mark. seems unnatural 
if form.is_valid() 
    return response... 
... #other code in standard format 
#send the user the form as 1)new 2)form errors 3)model errors 
return form 

如上代碼註釋:
一)難道這是一個習慣用法/好將模型錯誤轉移到表單的方法?

b)這是測試新「表單」錯誤的慣用/好方法嗎?

注意:本示例使用非現場錯誤,但我認爲它同樣適用於現場錯誤。

+0

我改變了選定的答案,因爲從斯特凡諾的更新實際上說服我去適應另一種方法([這裏組合的ModelForms方法之一](http://stackoverflow.com/questions/569468/django-multiple-models而不需要重新建模模型驗證和表單驗證之間的管道。(我不知道他們可以合併)。克里斯的回答對我的理解也很好。 – KobeJohn

回答

4

[編輯 - 希望這回答了你的評論]

我會簡短而直接,但不希望是不禮貌:)

1)模型驗證了表單驗證

我猜根據經驗法則,只要規則與模型真正相關,是的,最好在模型層面進行驗證。

對於多模式形成,請結帳這個其他SO問題:Django: multiple models in one template using forms,不忘attached link這是稍微老了,但仍然具有現實意義上實現它的dryest方式。在這裏重新討論這一切太長了!

2)

  • 一)不!你應該從ModelForm派生你的表單,它將爲你執行model validation - >你不需要自己調用模型驗證
  • b)不!如果你想驗證一個模型,你不應該試着去保存它;你應該使用full_clean - >所以如果你的ModelForm是有效的,那麼你知道該模型也是有效的,你可以保存。

是的,這些答案仍適用於多模型表單。

所以,你應該做的是:

  • 還在用的ModelForm
  • 不用擔心驗證的模型,因爲一會的ModelForm爲你做的。

一般來說,如果你發現自己用django做了一些管道工作,這是因爲還有另一種更簡單的方法來做到這一點!

第二屆指針應該讓你開始,實際上簡化代碼很多...

+0

第1部分)? – KobeJohn

+0

至於第2部分),讓我回答幾點以更好地理解。 a)在這種情況下,是的,我可以更乾淨地使用ModelForm。但是,我應該說我擁有包含幾個模型的表單,所以ModelForm不適合嗎?在這種情況下,我做得好嗎? b)不夠公平。自從到目前爲止,我更喜歡它,這是我找到的唯一組合。如果沒有問題,full_clean隨後保存。所以我只是將它們結合起來,而不是在每個領域都要記住它。更幹我想。 – KobeJohn

+0

@yakiimo希望我回答了您的其他問題 – Stefano

4

1)是的,這是完全有效的做模型驗證。這就是爲什麼Django人加入它。在保存模型的過程中並不總是使用表單,所以如果只通過表單完成驗證,則會遇到問題。當然,過去人們通過重寫save方法幷包含驗證方式來解決此限制。但是,新的模型驗證更具語義性,並在實際使用表單時爲您提供驗證過程的鉤子。

2)該文檔很清楚地表明,模型驗證(full_clean)在調用ModelForm.is_valid時運行。但是,如果您不使用ModelForm或想要進行其他處理,則需要手動撥打full_clean。你這樣做,但把它放在重寫的save是錯誤的方法。記住:「顯式比隱式更好。」此外,save在許多其他地方和方式中被調用,而在ModelForm的情況下,您實際上最終會以這種方式運行full_clean

也就是說,由於文檔說ModelForm會自動執行full_clean,所以我認爲看看它如何處理錯誤是有意義的。在_post_clean方法,開始行323的django.forms.models

# Clean the model instance's fields. 
try: 
    self.instance.clean_fields(exclude=exclude) 
except ValidationError, e: 
    self._update_errors(e.message_dict) 

# Call the model instance's clean method. 
try: 
    self.instance.clean() 
except ValidationError, e: 
    self._update_errors({NON_FIELD_ERRORS: e.messages}) 

反過來,在同一模塊的248線_update_errors啓動代碼:

def _update_errors(self, message_dict): 
    for k, v in message_dict.items(): 
     if k != NON_FIELD_ERRORS: 
      self._errors.setdefault(k, self.error_class()).extend(v) 
      # Remove the data from the cleaned_data dict since it was invalid 
      if k in self.cleaned_data: 
       del self.cleaned_data[k] 
    if NON_FIELD_ERRORS in message_dict: 
     messages = message_dict[NON_FIELD_ERRORS] 
     self._errors.setdefault(NON_FIELD_ERRORS, self.error_class()).extend(messages) 

你必須與打編碼一點,但是這應該給你一個很好的起點來組合表單和模型驗證錯誤。

+0

查看ModelForm的源代碼很好。那已經超出了我的想法,並隨後消失了。我現在會研究它。感謝您回覆的所有部分。 – KobeJohn

+0

查看開發代碼並進一步查看之後,看起來綽綽有餘的是在我的技能水平上徘徊不前。希望這些組合形式能夠解決。再次感謝回覆和領導。 – KobeJohn