使用内联时如何在 django-admin 中验证两个模型的数据? [英] How to validate data of two models in the django-admin when using inlines?

查看:22
本文介绍了使用内联时如何在 django-admin 中验证两个模型的数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:直接阅读 django 源代码,我得到了一个未记录的缺失部分来解决我的问题.感谢 Brandon 给了我一个缺失的部分,解决了一半的问题.查看我自己的答案以查看我的解决方案(我不想在这里混用).

Update: Reading directly the django source code i got one undocumented missing piece to solve my problem. Thanks to Brandon that solved half of the problem by giving me one of the missing pieces. See my own answer to see my solution (i dont want to mix things here).

我有以下(简化的)模型:

I have the following (simplified) models:

Order(models.Model):
    status = models.CharField( max_length=25, choices=STATUS_CHOICES, default='PENDING')
    total = models.DecimalField( max_digits=22, decimal_places=2)

    def clean(self):
        if self.estatus == 'PAID' or self.estatus == 'SENT':
            if len(self.payment.all()) > 0:
                raise ValidationError("The status cannot be SENT or PAID if there is no payment for the order")

Payment(models.Model):
    amount = models.DecimalField( max_digits=22, decimal_places=2 )
    order  = models.ForeignKey(Order, related_name="payment")

    def clean(self):
        if self.amount < self.order.total or self.amount <= 0:
            ValidationError("The payment cannot be less than the order total")

在我的 admin.py 我有:

In my admin.py i have:

class paymentInline(admin.StackedInline):
    model   = Payment
    max_num = 1

class OrderAdmin(admin.ModelAdmin):
    model   = Order
    inlines = [ paymentInline, ]

Order的clean方法中的验证不起作用,因为验证发生时没有保存付款(显然没有保存到数据库中).

The validation in the clean method of the Order does not work because there is no payment saved when the validation occurs (obviously it has not been saved to the database).

付款中的验证工作正常(如果编辑或添加新付款).

The validation inside the payment works fine (if editing or adding a new payment).

如果状态为已付款"或已发送",我想验证订单是否已付款,但因为我无法做到这一点,所以采用 clean 方法.

I want to validate if the order has a payment if the status is 'PAID' or 'SENT', but as i cannot doit the way is in the clean method.

我的问题是,如何访问用户在订单表单的内联(付款)中输入的payment.amount"值,以完成我的验证?(考虑 Order 模型的 clean 方法中的 im)

My question is, how can i access the 'payment.amount' value entered by the user in the inline (payment) of the Order form, to accomplish my validation? (considering im in the clean method of the Order model)

推荐答案

阅读 django 源代码后,我发现 BaseInlineFormSet 的一个属性包含内联的父实例,在我的例子中,是正在编辑的 Order 实例.

After reading the django source code i found one property of the BaseInlineFormSet that contains the Parent Instance of the Inline, in my case, the Order instance being edited.

Brandon 给了我另一个重要的部分,遍历 BaseInlineFormSet 的 self.forms 以获取每个实例(甚至未保存、未清理或清空),在我的例子中,每个支付实例都在被编辑.

Brandon gave me another important piece, iterating over the self.forms of the BaseInlineFormSet to get each of the instances (even not saved or not cleaned or empty), in my case, each Payment Instance being edited.

这是检查状态为已付款"或已发送"的订单是否已付款所需的两条信息.遍历formset的cleaned_data不会给出订单数据(即当不更改订单时,只是更改付款,或者当不添加付款 - 和一个空的付款 - 但更改订单时)需要决定保存如果订单状态不是 'PAID' 或 'SENT',则模型,因此该方法之前被丢弃.

These are the two pieces of information needed to check if the Order with status 'PAID' or 'SENT' has a payment or not. Iterate over the cleaned_data of the formset would not give Order data (i.e. when not changing the Order, just changing the Payment, or when not adding a Payment -and an empty Payment- but changing the Order) which is needed to decide to save the model if the order status is different than 'PAID' or 'SENT', so this method was discarded before.

模型保持不变,我只修改了admin.py添加下一个:

The models are keep the same, I only modified the admin.py to add the next:

class PaymentInlineFormset(forms.models.BaseInlineFormSet):
    def clean(self):
        order = None
        payment = None

        if any(self.errors):
            return

        # django/forms/models.py Line # 672,674 .. class BaseInlineFormSet(BaseModelFormSet) . Using Django 1.3
        order = self.instance

        #There should be only one form in the paymentInline (by design), so  in the iteration below we end with a valid payment data.
        if len(self.forms) > 1:
            raise forms.ValidationError(u'Only one payment per order allowed.')
        for f in self.forms:
            payment = f.save(commit=False)

        if payment.amount == None:
            payment.amount = 0

        if order != None:
            if order.status in ['PAID', 'SENT'] and payment.amount <= 0:
                raise forms.ValidationError(u'The order with %s status must have an associated payment.'%order.status)

class pymentInline(admin.StackedInline):
    model   = Payment
    max_num = 1
    formset = PaymentInlineFormset

class OrderAdmin(admin.ModelAdmin):
    inlines = [ paymentInline, ]

admin.site.register(Order, OrderAdmin)
admin.site.register(Payment)

这篇关于使用内联时如何在 django-admin 中验证两个模型的数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆