1

シナリオ:注文フォームを作成しています。地球上の他のすべての注文フォームと同様に、個別の請求先配送先住所があります。ユーザーが時間を節約できるように、[請求先住所を使用する]チェックボックスを追加しました。

問題は、出荷フィールドがまだそこにあるということです。ユーザーが配送先住所データを入力しない場合(請求先住所を使用する場合など)、検証に失敗します。

これらの重複フィールドの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.
4

2 に答える 2

2

私がただの狂信者であったかどうかはわかりませんが、次のことがうまくいきました(そして私の質問全体に答えます):

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

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が以下で指摘しているように、cleaned_dataは保証された順序で入力されていません。つまり、が呼び出されたship_to_billingときに存在しない可能性があります。これを回避する方法は、にアクセスする代わりclean_shipping_street()にメソッドを呼び出すことです。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()

または それよりもさらに良い:

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()が以前の作業よりもはるかに少なく呼び出されることを意味するはずです。しかし、真剣に、プロファイリングセッションでこれらの「改善」を検出することさえできないと思います。

于 2009-11-27T22:35:14.887 に答える
1

私の最後の答えにはいくつかの問題がありました。コピーされたデータはフォームにレンダリングされませんでした(私はあなたが望むものかもしれません)、そしてそれは少し信頼できませんでした。

これが私が今使っているものです。clean_field_name()何十もの定義を追加する代わりに、私はちょうど1つを持ってい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

オンにすると、請求フィールドの生データが出荷フィールドにコピーされます。モデル(またはフォーム)のフィールド順序で、フィールドが出荷フィールドの前にあることが重要です。

そして、POSTデータは不変であるため、self.dataをコピーしています。

于 2009-11-30T12:08:40.847 に答える