Django Modelform(带有排除字段)

时间:2011-04-18 16:38:43

标签: django validation forms

我有一个样本表格:

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'

这里的问题是'公司'不在那里,因为它被排除在外。 在这种情况下,提出表单验证错误的最佳方法是什么?

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

2 个答案:

答案 0 :(得分:11)

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

修改

你可以做一些事情来捕捉非独特的一起进入尝试。

  1. 在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:
            ...
    
  2. 在模型表单的clean方法中使用self.instance来检查唯一性。

答案 1 :(得分:2)

你可以试试这个:

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

docs说:默认情况下,clean()方法会验证标记为... unique_together

的字段的唯一性