当使用内联线时,如何在django管理中验证两个模型的数据?

当使用内联线时,如何在django管理中验证两个模型的数据?,django,django-models,django-admin,Django,Django Models,Django Admin,更新:直接阅读django源代码,我得到了一个未记录的缺失片段来解决我的问题。多亏了布兰登,他给了我一件丢失的东西,解决了一半的问题。看看我自己的答案,看看我的解决方案(我不想在这里混为一谈) 我有以下(简化)模型: 订单的clean方法中的验证不起作用,因为在进行验证时没有保存付款(显然它没有保存到数据库) 付款内的验证工作正常(如果编辑或添加新付款) 如果订单状态为“已支付”或“已发送”,我想验证订单是否已付款,但由于我无法这样做,因此使用clean方法 我的问题是,如何访问用户在订单内联(

更新:直接阅读django源代码,我得到了一个未记录的缺失片段来解决我的问题。多亏了布兰登,他给了我一件丢失的东西,解决了一半的问题。看看我自己的答案,看看我的解决方案(我不想在这里混为一谈)

我有以下(简化)模型:

订单的clean方法中的验证不起作用,因为在进行验证时没有保存付款(显然它没有保存到数据库)

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

如果订单状态为“已支付”或“已发送”,我想验证订单是否已付款,但由于我无法这样做,因此使用clean方法


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

听起来您只需要验证内联中是否至少有一个有效的表单集……您可以尝试一下以下代码:

希望这能让你走

[编辑]

我查看了我为另一个应用程序编写的一些代码,该应用程序基于相关模型的属性对内联线进行自定义验证。当然,您可能需要进行一些调整,但请尝试一下。您还需要指定要在管理模型中使用的内联

#I would put this in your app's admin.py
class PaymentInline(admin.TabularInline):
    model = Payment
    formset = PaymentInlineFormset

#I would put this in the app's forms.py
class PaymentInlineFormset(forms.models.BaseInlineFormSet):
        def clean(self):
            order = None
            valid_forms = 0

            for error in self.errors:
                if error:
                    return

            for cleaned_data in self.cleaned_data:
                amount = cleaned_data.get('amount', 0)
                if order == None:
                    order = cleaned_data.get('order')
                if amount > 0:
                    valid_forms += 1

            if order.status in ['PAID', 'SENT'] and len(valid_forms) > 0:
                raise forms.ValidationError(u'Your error message')

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

Brandon给了我另一个重要的部分,迭代BaseInlineFormSet的self.forms以获得每个实例(即使未保存、未清理或为空),在我的例子中,每个支付实例都在编辑中

这是检查状态为“已付款”或“已发送”的订单是否已付款所需的两条信息。如果订单状态不同于“已支付”或“已发送”,则迭代表单集的已清理的_数据不会给出订单数据(即,当不更改订单时,仅更改付款,或当不添加付款-和空付款-但更改订单时),这是决定保存模型所需的数据,因此以前已放弃此方法

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

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)
class PaymentInlineFormset(forms.models.BaseInlineFormSet):
def清洁(自清洁):
订单=无
付款=无
如果有(自身错误):
返回
#django/forms/models.py行#672674。。类BaseInlineFormSet(BaseModelFormSet)。使用Django 1.3
order=self.instance
#paymentInline中应该只有一个表单(根据设计),因此在下面的迭代中,我们以有效的支付数据结束。
如果len(self.forms)>1:
raise forms.ValidationError(每个订单只允许一次付款)。)
对于以self.forms表示的f:
付款=保存(提交=错误)
如果payment.amount==无:
付款金额=0
如果有订单!=无:

如果订单状态为“已支付”、“已发送”且付款金额为[“已支付”、“已发送”,则我只需在订单状态为“已支付”或“已发送”时要求内联中的有效表单集。任何其他状态都可能允许用户保存模型而不保存内联数据(空数据)。问题是如何从每个模型表单(正在编辑的主模型和内联模型)中访问这些字段(数据)以进行比较。应该可以获取与内联线相关的父对象的引用。我将看看明天是否可以为您提供一个工作示例。我添加了一个编辑,显示一个自定义的内联表单集,该表单集可能适合您。self.cleaned_数据为空:[{}]当Payment(留空)self.cleaned_数据中没有数据为空时,我原以为它将填充Order cleaned_数据,但它是PaymentInlineFormSet。
#I would put this in your app's admin.py
class PaymentInline(admin.TabularInline):
    model = Payment
    formset = PaymentInlineFormset

#I would put this in the app's forms.py
class PaymentInlineFormset(forms.models.BaseInlineFormSet):
        def clean(self):
            order = None
            valid_forms = 0

            for error in self.errors:
                if error:
                    return

            for cleaned_data in self.cleaned_data:
                amount = cleaned_data.get('amount', 0)
                if order == None:
                    order = cleaned_data.get('order')
                if amount > 0:
                    valid_forms += 1

            if order.status in ['PAID', 'SENT'] and len(valid_forms) > 0:
                raise forms.ValidationError(u'Your error message')
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)