The Jammon method is the one I use. To expand a bit (using your example):
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))
This works by creating an instance of your discount model and then linking your form to that instance. This instance is not stored in your db, but is used to bind the form. This related form is relevant to the associated instance company. Then it is sent to your template for completion by the user. When the user submits this form and the form is verified, the model validation check verifies the uniqueness of the unique population defined in the meta.
See Model Validation Docs and overriding clean for ModelForms
change
There are a few things you can do to catch unique recording attempts.
Inside form.is_valid (), you can throw an Integrity error:
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: ...
Use self.instance in a pure model form method to verify uniqueness.
source share