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

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

问题描述

更新:直接阅读django源代码,我有一个未记录的缺失的部分来解决我的问题。感谢布兰登,通过给我一个缺失的部分解决了一半的问题。看到我自己的解决方案(我不想在这里混合)。



我有以下(简化)模型:

 订单(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):
如果self.estatus =='PAID'或self.estatus =='SENT ':
如果len(self.payment.all())> 0:
raise ValidationError(如果订单没有付款,状态不能为SENT或PAID)

付款(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或self.amount< = 0:
ValidationError(付款不能低于订单总额)

在我的admin.py我有:

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

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

订单的清洁方法中的验证不起作用,因为验证发生时没有保存付款显然没有保存到数据库中)。



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



如果状态为PAID或SENT,我想验证订单是否已付款,但是我无法以干净的方式执行此操作。我的问题是,我如何访问用户在订单表单的内线(付款)中输入的'payment.amount'值,以完成我的验证? (考虑到在订单模型的干净方法中)

解决方案

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



布兰登给了我另一个重要的部分,迭代了BaseInlineFormSet的self.forms获取每个实例(甚至不保存或不清除或空白),在我的情况下,每个付款实例正在编辑。



这些是需要的两个信息检查状态为PAID或SENT的订单是否付款。在formset的purge_data上迭代不会给出订单数据(即,当不更改订单,只是更改付款,或不添加付款,或者不添加付款,而是添加一个空的付款 - 但是更改订单)时,决定保存如果订单状态不同于PAID或SENT,那么这种方法在之前被丢弃。



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

  class PaymentInlineFormset(forms.models.BaseInlineFormSet):
def clean(self) :
订单=无
付款=无

如果有(self.errors):
返回

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

#paymentInline(按设计)应该只有一个表单,所以在下面的迭代中,我们结束一个有效的付款数据。
如果len(self.forms)> 1:
raise forms.ValidationError(你只需支付一个订单就可以)'
for f in self.forms:
payment = f.save(commit = False)

如果payment.amount ==无:
payment.amount = 0

如果订单!=无:
如果order.status在['PAID' 'SENT']和payment.amount< = 0:
raise forms.ValidationError(u'具有%s状态的订单必须有相关的付款'%order.status)

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

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

admin.site.register(Order,OrderAdmin)
admin.site.register(付款)


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

In my admin.py i have:

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

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

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

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.

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)

解决方案

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 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.

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.

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天全站免登陆