Opened 7 years ago

Closed 7 years ago

Last modified 4 years ago

#8795 closed (fixed)

unique_together validation fails on model forms that exclude unique fields

Reported by: anihrat@… Owned by: jacob
Component: Forms Version: master
Severity: Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description (last modified by telenieko)

i found this bug

when you have model like this:

class FunkcjeProdukt(models.Model):
    funkcja = models.ForeignKey(FunkcjeRodzina)
    produkt = models.ForeignKey(Produkty)
    wartosc = models.CharField(max_length=255)
    class Meta:
        unique_together = ("produkt", "funkcja")

and form from model:

class FunkcjeProduktForm(ModelForm):
    wartosc = forms.CharField(widget=forms.TextInput(attrs={'size':'40','class':'formularz'}))
    class Meta:
        model = FunkcjeProdukt

end if you want only edit "wartosc" from existing instance:

form_fp = FunkcjeProduktForm(data=request.POST,instance=finst)
if form_fp.is_valid():

error is throw:

KeyError at /cms/r_produkt/8/'produkt'
Request Method:    POST
Request URL:
Exception Type:    KeyError
Exception Value:    'produkt'
Exception Location:    /home/posiflex/django/forms/ in validate_unique, line 238

in validate_unique() from django/forms/
line unique_checks = list(self.instance._meta.unique_together[:])
add 'produkt' and 'funkcja' even when this fields in on exclude list

Attachments (1)

django-8795.diff (1.2 KB) - added by Alex 7 years ago.
Fixes problem with the test case to prove it

Download all attachments as: .zip

Change History (13)

comment:1 Changed 7 years ago by telenieko

  • Description modified (diff)
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Rewrote Description to hightlight code and not mess with it.

comment:2 Changed 7 years ago by jacob

  • Summary changed from bug in form validation to unique_together validation fails on model forms that exclude unique fields

(Changed title so I'll understand what's going on quicker.)

comment:3 Changed 7 years ago by julien

My call here is "don't do that". You shouldn't save the form if you know the model instance can't be complete. It's actually normal that it fails: the form is valid, the instance is not.

If for example you had a required field your model, but that was excluded in the form. would also fail, and for a good reason.

I would use in your code instead, and then manually fix the problematic fields.

comment:4 Changed 7 years ago by anonymous

instance is valid im 100% sure, in this situation first program create instance with "produkt" and "funkcja" complete then in other place user can only modified one field "wartosc" and this traceback show this place:

lookup_kwargs[field_name] = self.cleaned_data[field_name]

this list self.cleaned_data doesnt have 'produkt' key so bug truly exist

Changed 7 years ago by Alex

Fixes problem with the test case to prove it

comment:5 Changed 7 years ago by jacob

  • Owner changed from nobody to jacob
  • Status changed from new to assigned
  • Triage Stage changed from Unreviewed to Accepted

It's not that's failing; it's form.is_valid(); this is indeed a bug. It's a pretty easy fix; I'll have it done soon.

comment:6 Changed 7 years ago by jacob

Er, or maybe I'll just use Alex's fix :)

comment:7 Changed 7 years ago by anonymous

Alex's fix is working just fine :)

comment:8 Changed 7 years ago by jacob

  • Resolution set to fixed
  • Status changed from assigned to closed

(In [8854]) Fixed #8795: unique_together validation no longer fails on model forms that exclude fields included in the check. Thanks, Alex Gaynor.

comment:9 Changed 7 years ago by oliverandrich

A question concerning the fix.

Given a model like that:

class Project(models.Model):
    name         = models.CharField(_('Name'), max_length=255)
    creator      = models.ForeignKey(User, verbose_name=_('Ersteller'), related_name='projects') 
    class Meta:
        unique_together     = ('name', 'creator')

And a form like that:

class ProjectForm(forms.ModelForm):
    class Meta:
        model   = Project
        fields  = ['name']

form.is_valid() doesn't report the failed constraint, only when I include in the creator field in the fields array too. Seems as the check is broken (or impossible), if only one part of the unique_together constraint is inside the fields list.

Is this a bug or just a case I have to live with, cause it is not solvable?

comment:10 Changed 7 years ago by julien

If you can come up with a test case which is similar to the one added in [8854] and which fails, then yes, you should reopen this ticket.

comment:11 Changed 7 years ago by mtredinnick

In reply to comment:9, the form is valid. The unique_together constraint is only applicable to the model and thus is only going to kick in at save time at the moment. With the model-aware validation work in progress, there'll be an extra step to check the model validity as well, prior to saving so that validation errors there can be handled properly rather than being raised out of save().

comment:12 Changed 4 years ago by jacob

  • milestone 1.0 deleted

Milestone 1.0 deleted

Note: See TracTickets for help on using tickets.
Back to Top