2009-11-27 67 views
1

場景:我正在構建訂單表單。像地球上的其他訂單一樣,它具有單獨的發票寄送地址。我剛剛添加了「使用帳單地址」複選框,以讓用戶節省時間。如果設置了BooleanField,則只驗證某些字段

問題是,運輸領域仍然存在。如果用戶沒有輸入任何送貨地址數據(如他們想使用賬單地址),他們將失敗驗證。

我覺得我想要做的覆蓋爲這些重複字段的ModelForm驗證。在那裏,如果該框被選中(不知道如何從驗證器中獲取數據),我會返回結算版本。如果沒有選中,我會將其傳回原始驗證。

聽起來像一個計劃不是嗎?好吧,我摔倒在第一個障礙。我的clean_functions不起作用。看起來不像他們甚至被稱爲。

下面是一些代碼:

# shipping_street is a field in my Order Model 

class OrderForm(ModelForm): 
    class Meta: 
     model = Order 

    def clean_shipping_street(self): 
     print "JUST GET ME SOME OUTPUT!!!" 
     raise forms.ValidationError('RAWRAWR') 

這裏是我是如何測試:

def checkout(request): 
    of = OrderForm() 
    if request.method == "POST": 
     of = OrderForm(request.POST) 
     print 'Form valid:', of.is_valid() 

    # ... 
    # return my HttpResponse with 'of' in the context. 

回答

1

我最後的答案有幾個問題。複製的數據沒有回覆到表格中(可能是你想要的東西,我是這樣做的),並且它有點不可靠。

這是我現在使用的。而不是增加幾十clean_field_name()定義的,我有一個剛上BooleanField

def clean_ship_to_billing(self): 
    if self.cleaned_data.get('ship_to_billing', False): 
     data = self.data.copy() 
     for f in ['street', 'street_2', 'post_code', 'city', 'county', 'country', ]: 
      data['shipping_%s' % f] = data['billing_%s' % f] 
     self.data = data 

如果選中,它會將整個計費領域的原始數據轉化爲運輸領域。該字段位於模型(或表單)字段順序中的發貨字段之前,這一點很重要。

而我正在複製self.data,因爲POST數據是不可變的。

2

我不知道如果我只是做了clutz但下面的工作(和答案我的整個問題):

類OrderForm(的ModelForm): 類元: 模型=訂單

def clean_shipping_street(self): 
    print 'VALIDATING!!! YEY!' 
    if self.cleaned_data['ship_to_billing']: 
     return self.clean_billing_street() 
    return super(OrderForm, self).clean_shipping_street() 

但如果你認爲我會對此錯誤的方式,請讓我知道!

由於Nick在下面指出,cleared_data沒有填寫保證順序,這意味着當調用clean_shipping_street()ship_to_billing可能不存在。解決方法是調用clean_shipping_street()方法,而不是訪問cleaned_data

def clean_shipping_street(self): 
    print 'VALIDATING!!! YEY!' 
    if self.clean_ship_to_billing(): 
     return self.clean_billing_street() 
    return super(OrderForm, self).clean_shipping_street() 

如果你不懶,因爲我是當我寫的代碼,你可能要避免布爾現場這麼多的重複驗證。這應該是更快的(提供的默認域不運行,除非它的需要 - 不知道對自己):

def clean_shipping_street(self): 
    print 'VALIDATING!!! YEY!' 
    if self.cleaned_data.get('ship_to_billing', self.clean_ship_to_billing): 
     return self.clean_billing_street() 
    return super(OrderForm, self).clean_shipping_street() 

OR甚至比這更好:

def clean_shipping_street(self): 
    if not self.cleaned_data.has_key['ship_to_billing']: 
     self.cleaned_data['ship_to_billing'] = self.clean_ship_to_billing() 
    if self.cleaned_data['ship_to_billing']: 
     return self.clean_billing_street() 
    return super(OrderForm, self).clean_shipping_street() 

這只是略有不同,但它應該意味着clean_ship_to_billing()被調用的次數比我以前的努力少得多。但嚴重的是,我懷疑你甚至可以在分析會話中檢測到這些「改進」。

+1

這是我會這樣做的方式。也許不是最好的,但定製的清潔方法可能是最簡單的。 – 2009-11-28 04:28:58

+1

請注意,'clean_ '方法沒有以任何特定的順序調用,所以在上面的'ship_to_billing'中可能沒有設置''cleaned_data'。一般情況下,如果你的清潔方法依賴於表單中的多個項目,請使用普通的'clean'方法。 – 2009-11-28 16:51:30

+0

我對尼姆有個想法。而不是調用'self.cleaned_data ['field_name']',稱爲'self.clean_field_name()' - 這樣就保證了結果(除非您的自定義清除具有混亂的循環依賴)。這對於CPU來說有點多,但它應該始終有效。 – Oli 2009-11-29 01:47:28

相關問題