2012-10-23 43 views
23

我仍然試圖理解在模型級使用自定義驗證器來驗證Django模型對象的正確方法。我知道驗證通常是在表單或模型表單中完成的。但是,如果我通過Python shell中的ORM與它交互,我希望確保模型級別數據的完整性。這是我目前的做法:驗證Django模型對象的正確方法?

from django.db import models 
from django.core import validators 
from django.core exceptions import ValidationError 


def validate_gender(value): 
    """ Custom validator """ 
    if not value in ('m', 'f', 'M', 'F'): 
     raise ValidationError(u'%s is not a valid value for gender.' % value) 


class Person(models.Model): 
    name = models.CharField(max_length=128) 
    age = models.IntegerField() 
    gender = models.CharField(maxlength=1, validators=[validate_gender]) 

    def save(self, *args, **kwargs): 
     """ Override Person's save """ 
     self.full_clean(exclude=None) 
     super(Person, self).save(*args, **kwargs) 

這裏是我的問題:

  1. 我應該創建一個自定義的驗證功能,將其指定爲驗證,然後覆蓋人的save()函數,我上面做過嗎? (順便說一下,我知道我可以使用「選擇」字段選項來驗證我的性別選擇,但爲了說明的目的我創建了「validate_gender」)。

  2. 如果我真的保證我的數據的完整性,應該我不僅使用Python/Psycopg寫在模型層測試Django的單元測試,但也相當於數據庫級的單元測試?我注意到引發ValidationErrors的Django單元測試僅使用數據庫副本測試模型對數據庫模式的理解。即使我使用South進行遷移,任何數據庫級別的約束都僅限於Django可以理解並轉換成Postgres約束的內容。如果我需要Django無法複製的自定義約束,那麼如果我通過psql終端直接與數據庫交互,我可能會將數據輸入到違反該約束的數據庫中。

謝謝!

+0

我不知道問題1如何是你以前對這個主題的問題不同。請注意,它仍然不會阻止您使用ORM插入無效數據。考慮Person.objects.update(gender ='a')'。 – Alasdair

+1

除了在我之前的問題中,我沒有像我在這裏那樣包含自定義驗證器函數,您是對的。至於你對.update的其他觀察,我想我現在有一個額外的問題,這增加了我的困惑。我真的很難理解什麼是正確的做法。雖然Django文檔相當不錯,但恕我直言,他們很長時間在片段和「揮手」上,但缺乏完整的示例幫助像我這樣的「新手」瞭解解決此問題的正確方法。不幸的是,我一個人工作,沒有更多有經驗的開發人員來討論這個問題。 – William

回答

16

我剛開始使用Django時,對ORM有類似的誤解。

1)不,請勿將self.full_clean()放入save的內部。無論是

A)使用ModelForm(這將導致發生的所有相同的驗證 - 注:ModelForm.is_valid()不會叫Model.full_clean明確,但將執行完全相同的支票Model.full_clean)。例如:

class PersonForm(forms.ModelForm): 
    class Meta: 
     model = Person 

def add_person(request): 
    if request.method == 'POST': 
     form = PersonForm(request.POST, request.FILES) 
     if form.is_valid(): # Performs your validation, including ``validate_gender`` 
      person = form.save() 
      return redirect('some-other-view') 
    else: 
     form = PersonForm() 
     # ... return response with ``form`` in the context for rendering in a template 

還要注意,形式不使用只在使它們在模板中的觀點 - 他們對任何形式使用的是偉大的,包括API等運行form.is_valid()並獲得錯誤後,您將擁有form.errors這是一個包含表單中所有錯誤的字典,其中包含一個名爲'__all__'的密鑰,該密鑰將包含非字段錯誤。 B)只需在您的視圖(或其他邏輯應用程序層)中使用model_instance.full_clean(),而不是使用表單,但表單對於此來說是一個很好的抽象。

2)我真的沒有解決辦法,但我從來沒有碰到這樣的問題,即使在大項目(目前的項目,我與我的公司工作,擁有146臺),我不懷疑它會成爲你的情況。

+2

您是否在說我應該使用表單或模型表單來驗證我的數據模型,即使我沒有真正將模型對象以實際模板形式呈現給用戶?謝謝。 – William

+1

@RobertF。 - 這是正確的。無論是更新還是創建實例,即使您不打算在模板中顯示錶單,「ModelForm」類都是模型驗證的體面抽象。 – orokusaki

+1

你說要麼A)做到這一點,什麼是選項B? – rgenito