Django Modelform(带有排除字段)

Posted

技术标签:

【中文标题】Django Modelform(带有排除字段)【英文标题】:Django Modelform (with excluded field) 【发布时间】:2011-08-08 01:00:12 【问题描述】:

我有一个样本表格:

class AdminDiscountForm(ModelForm):  
    class Meta:  
        model = Discount  
        exclude = ('company',)

它指向的模型是:

class Discount(models.Model):
    class Meta:
        verbose_name=_('Discount')
        verbose_name_plural=_('Discounts')
        unique_together = ('company','type')

    company = models.ForeignKey(Company)
    type = models.CharField(max_length=5, choices=DISCOUNT_CHOICES)
    discount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name=_('Discount'))

表单不包括“公司”字段,因为用户已经使用 UI 选择了此字段。

我打算做一个:

company = blah
if form.is_valid():
    obj = form.save(commit=False)
    obj.company = company
    obj.save()

问题是'company' 和'type' 的组合应该是唯一的(因此是'unique_together')。这是在数据库中强制执行的,所以 django 不在乎。 我需要扩展这个表单的 clean() 方法来检查唯一性:

def clean(self):
    cleaned_data = self.cleaned_data
    # check for uniqueness of 'company' and 'type'

这里的问题是“公司”不在其中,因为它已被排除在外。 在这种情况下引发表单验证错误的最佳方法是什么?

-- 编辑 这仅适用于添加折扣条目。 没有初始实例。

【问题讨论】:

在这里找到答案:***.com/questions/2141030/… 【参考方案1】:

Jammon 的方法是我使用的方法。扩展一点(使用您的示例):

models.py

class Discount(models.Model):
    class Meta:
        verbose_name=_('Discount')
        verbose_name_plural=_('Discounts')
        unique_together = ('company','type')

    company = models.ForeignKey(Company)
    type = models.CharField(max_length=5, choices=DISCOUNT_CHOICES)
    discount = models.DecimalField(max_digits=7, decimal_places=2, verbose_name=_('Discount'))

forms.py

class AdminDiscountForm(ModelForm):  
    class Meta:  
        model = Discount  
        exclude = ('company',)

views.py

def add_discount(request, company_id=None):
    company = get_object_or_404(Company, company_id)

    discount=Discount(company=company)

    if request.method == 'post':
        form = AdminDiscountForm(request.POST, instance=discount)
        if form.is_valid():
            form.save()
            return HttpResponse('Success')
    else:
        form = AdminDiscountForm(instance=company)

    context =  'company':company,
                'form':form,

    return render_to_response('add-discount.html', context,
        context_instance=RequestContext(request))

这是通过创建折扣模型的实例,然后将表单绑定到该实例来实现的。此实例不会保存到您的数据库中,而是用于绑定表单。此绑定表单具有绑定实例的公司的值。然后将其发送到您的模板供用户填写。当用户提交此表单并验证表单时,模型验证检查将检查 Meta 中定义的唯一性的唯一性。

Model Validation Docsoverriding clean for ModelForms

编辑:

您可以做一些事情来捕捉非唯一的一起进入尝试。

    在您的 form.is_valid() 中,您可以排除这样的完整性错误:

    if request.method == 'post':
        form = AdminDiscountForm(request.POST, instance=discount)
        if form.is_valid():
            try:
                form.save()
                return HttpResponse('Success')
            except IntegrityError:
                form._errors["company"] = "some message"
                form._errors["type"] = "some message"
        else:
            ...
    

    在模型表单的 clean 方法中使用 self.instance 来检查唯一性。

【讨论】:

我明白了。我对 Discount() 感到困惑。我以为是 Discount.objects.create()。我的错。谢谢你们俩。 虽然现在没问题,但我仍然收到 IntegrityError,因为由于其中一个字段已被排除,所以没有发生对 unique_together 的验证。 不需要。我可以以 clean() 方法访问实例吗?我去看看。 所以基本上我可以从 clean() 中访问 self.instance.company 来进行验证。凉爽的。感谢您的帮助! “此外,绑定到模型对象的模型表单实例将包含一个 self.instance 属性,该属性使模型表单方法可以访问该特定模型实例。”,啊,我明白了。好的。用另一种可能的方法编辑帖子。【参考方案2】:

你可以试试这个:

discount = Discount(company = blah)
form = AdminDiscountForm(request.POST, instance=discount)
if form.is_valid():
    discount = form.save()

docs 说:默认情况下 clean() 方法验证标记为的字段的唯一性... unique_together

【讨论】:

我应该指出,这只是为了添加。根本没有编辑。 没关系。您创建一个设置了默认值的实例,然后该实例采用 ModelForm 中的所有其他值。 我当然不能每次都使用默认值创建一个实例。 unique_together 将在某个时候发挥作用。

以上是关于Django Modelform(带有排除字段)的主要内容,如果未能解决你的问题,请参考以下文章

Django - 带有 ModelForm 的属性和重新定义的字段?

Django的ModelForm组件

Django:带有条件的ModelForm

Django之ModelForm组件

Django之ModelForm组件

Django之ModelForm组件