【问题标题】:Django form validation depending on data in formsetDjango 表单验证取决于表单集中的数据
【发布时间】:2012-12-30 00:07:20
【问题描述】:

我有以下代码:

from django import forms
from django.core.exceptions import ValidationError

class MyAdminForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def clean(self):
        cleaned_data = self.cleaned_data
        max_num_items = cleaned_data['max_num_items']
        inline_items = cleaned_data.get('inlineitem_set', [])

        if len(inline_items) < 2:
            raise ValidationError('There must be at least 2 valid inline items')

        if max_num_items > len(inline_items):
            raise ValidationError('The maximum number of items must match the number of inline items there are')

        return cleaned_data

我以为我可以从cleaned_data 访问表单集(通过使用cleaned_data['inlineitem_set']),但似乎并非如此。

我的问题是:

  1. 如何访问表单集?
  2. 我是否需要使用自定义验证创建自定义表单集才能使其正常工作?
  3. 如果我需要这样做,如何在其clean 方法中访问表单集的“父”表单?

【问题讨论】:

  • 很抱歉,我不能投票赞成这个问题,但我不能这样做,因为它已被回答,但答案尚未被接受。

标签: django validation django-forms django-admin


【解决方案1】:

我刚刚为我自己的项目解决了这个问题。正如您在第二个问题中所建议的那样,似乎任何需要访问父表单的内联表单集验证都需要在 BaseInlineFormset 子类的 clean 方法中。

令人高兴的是,父表单的实例在调用内联表单集的 clean 之前被创建(或从数据库中检索,如果您正在修改而不是创建它),并且它可以作为 self.instance 在那里使用。

from django.core.exceptions import ValidationError
class InlineFormset(forms.models.BaseInlineFormSet):
    def clean(self):
        try:
            forms = [f for f in self.forms
                       if  f.cleaned_data
                       # This next line filters out inline objects that did exist
                       # but will be deleted if we let this form validate --
                       # obviously we don't want to count those if our goal is to
                       # enforce a min or max number of related objects.
                       and not f.cleaned_data.get('DELETE', False)]
            if self.instance.parent_foo == 'bar':
                if len(forms) == 0:
                    raise ValidationError(""" If the parent object's 'foo' is
                    'bar' then it needs at least one related object! """)
        except AttributeError:
            pass

class InlineAdmin(admin.TabularInline):
    model = ParentModel.inlineobjects.through
    formset = InlineFormset

这里的 try-except 模式是为了防止 AttributeError 极端情况,我自己没见过,但是当我们尝试访问失败的表单(在self.forms 中)的cleaned_data 属性时显然会出现这种情况验证。从https://stackoverflow.com/a/877920/492075了解到这个

(注意:我的项目仍在 Django 1.3 上;在 1.4 中没有尝试过)

【讨论】:

  • 从 Django 1.8 开始,当 admin 调用 clean() 方法时,InlineFormsetinstance 成员仍然被填充。谢谢!
  • 我在 Django 1.9 中做了一些非常相似的事情,而且效果很好。我要添加的一件事是在覆盖的 clean 函数的顶部添加 super(InlineFormset, self).clean(),使您可以访问表单集中每个表单上的 cleaned_data
猜你喜欢
  • 2020-05-01
  • 1970-01-01
  • 2016-03-15
  • 1970-01-01
  • 2011-09-17
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-02
相关资源
最近更新 更多