Django ModelForm(带排除字段)

15

我有一个样本表单:

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







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'

问题在于“company”未包含在其中,因为它已被排除。 在这种情况下,引发表单验证错误的最佳方法是什么?

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


答案在这里找到:https://dev59.com/7nI95IYBdhLWcg3wzhZ9 - gladysbixly
2个回答

15

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中定义的唯一在一起的唯一性。
请参阅模型验证文档覆盖ModelForms的clean方法 编辑: 您可以执行几个操作来捕获非唯一在一起的条目尝试。
  1. Inside your form.is_valid() you can except an Integrity Error like this:

    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:
            ...
    
  2. Use self.instance within the model form's clean method to check for uniqueness.


我明白了。我对Discount()感到困惑。我以为它是Discount.objects.create()。我的错。谢谢你们两个。 - Dim
虽然现在看起来没问题了,但是我仍然会收到IntegrityError的错误提示,因为unique_together的验证没有发生,这是因为其中一个字段已被排除在外。 - Dim
我可以在clean()方法中访问实例吗?我会去检查一下。 - Dim
所以基本上我可以在clean()函数内访问self.instance.company来进行验证。很棒,感谢你的帮助! - Dim
此外,与模型对象绑定的模型表单实例将包含一个self.instance属性,使得模型表单方法可以访问该特定的模型实例。啊,我明白了。很好。编辑帖子并提供了另一种可能的方法。 - dting

3
您可以尝试这个:
discount = Discount(company = blah)
form = AdminDiscountForm(request.POST, instance=discount)
if form.is_valid():
    discount = form.save()

文档中提到:默认情况下,clean() 方法会验证标记为unique_together的字段的唯一性...


我应该指出,这仅适用于添加。完全没有编辑。 - Dim
没问题。您可以创建一个实例并设置默认值,然后该实例将获取 ModelForm 中的所有其他值。 - jammon
我肯定不能每次都使用默认值创建实例。unique_together 在某个时候会生效。 - Dim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接