仅当设置了 BooleanField 时才验证某些字段

发布于 2024-08-12 10:51:28 字数 862 浏览 8 评论 0原文

场景:我正在构建一个订单。与地球上所有其他订单一样,它有单独的发票送货地址。我刚刚添加了“使用帐单地址”复选框,以让用户节省时间。

问题是,运输场仍然存在。如果用户不输入任何送货地址数据(例如他们想使用帐单地址),他们将无法通过验证。

我想我想要覆盖这些重复字段的 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.

Scenario: I'm building an order-form. Like every other order-form on the planet, it has separate invoicing shipping addresses. I've just added a "Use billing address" checkbox to let the user save time.

The problem is, the shipping fields are still there. They will fail validation if the user don't enter any shipping address data (like if they want to use the billing address).

What I think I'd like to do override the ModelForm validation for these duplicate fields. In there, if the box is checked (not sure how I get that data from within a validator), I return the billing version. If it's not checked, I pass it back to the original validation.

Sounds like a plan doesn't it? Well I fell at the first hurdle. My clean_functions aren't working. Doesn't look like they're even being called.

Here's some code:

# 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')

Here's how I'm testing:

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

三五鸿雁 2024-08-19 10:51:28

我不确定我是否只是一个笨蛋,但以下方法有效(并回答了我的整个问题):

class OrderForm(ModelForm):
类元:
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 未按保证顺序填充,这意味着在调用 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() 被调用的次数比我之前的努力要少得多。但说真的,我怀疑您甚至可以在分析会话中检测到这些“改进”。

I'm not sure if I was just being a clutz but the following worked (and answers my whole question):

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()

But if you think I'm going about this the wrong way, please let me know!

As Nick points out below, cleaned_data isn't filled in a guaranteed order, meaning ship_to_billing might not exist when clean_shipping_street() is called. The way around this is to call the clean_shipping_street() method instead accessing 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()

If you weren't as lazy as I was when I wrote the code, you might want to avoid so many duplicate validations of the boolean field. This should be faster (provided the default field isn't run unless it's needed - not sure on that myself):

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 even better than that:

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()

It's only slightly different but it should mean clean_ship_to_billing() gets called a lot less than my previous efforts. But seriously, I doubt you could even detect these "improvements" in a profiling session.

帅哥哥的热头脑 2024-08-19 10:51:28

我上次的回答有几个问题。复制的数据没有呈现回表单中(可能是您想要的,我就是这样做的)并且它有点不可靠。

这是我现在正在使用的。我没有添加数十个 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 数据是不可变的。

There were several problems with my last answer. Copied data wasn't rendered back into the form (might be something you want, I do) and it was a little unreliable.

Here is what I'm using now. Instead of adding dozens of clean_field_name() definitions, I have one just on the 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

If checked, it copies the raw data across for billing fields into shipping fields. It's important that the field is before the shipping fields in the model's (or form's) field order.

And I'm copying self.data because the POST data is immutable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文