UniqueConstraint raises uncaught IntegrityError in Admin

2,383 views
Skip to first unread message

Ryan Jarvis

unread,
Apr 9, 2019, 7:29:53 AM4/9/19
to Django users
Hey there,

I'm trying out the new UniqueConstraint functionality in Django 2.2 and seem to be misunderstanding something.  When adding a Constraint to the model I am getting an uncaught IntegrityError in the admin.  
I've got the following sample code:

models.py

class Seminar(models.Model):
    seminar_id = models.CharField(max_length=255, unique=True)
    members = models.ManyToManyField(User, through='SeminarRole', related_name="studies")

class SeminarRole(models.Model):
    LEAD = 1  # Only 1 Lead permitted per seminar
    SUPPORT = 2
    ROLE_CHOICES = (
        (LEAD, 'Lead'),
        (SUPPORT, 'Support'),
    )

    user = models.ForeignKey(User, related_name='seminar_roles', on_delete=models.CASCADE)
    seminar = models.ForeignKey('seminar', related_name='roles', on_delete=models.CASCADE)

    role = models.IntegerField(choices=ROLE_CHOICES)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['seminar'], condition=Q(role=1), name="only_one_lead"),
        ]



For the code above in the Django Admin I can successfully add a SeminarRole with User1 as the Lead for SeminarA, User2 as the Lead for SeminarB, and User1 as Support for SeminarB but if I try and add User2 as another Lead to SeminarA it gives me an Exception.  Should I be seeing the Django Admin catch this before hand?

IntegrityError at /admin/study_management/seminarrole/add/
duplicate key value violates unique constraint "only_one_lead"
DETAIL:  Key (seminar_id)=(1) already exists.


I'm on Django 2.2, Python 3.7 and Postgres 11.2

Robin Riis

unread,
Apr 9, 2019, 7:41:42 AM4/9/19
to django...@googlegroups.com
The Integrity error means that there is a row in the database with role = 1
So another row with role=1 would break the unique constraint and is not allowed.

So either remove the unique constraint or make sure it will be unique.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/fb2ab520-178d-4a0c-acf7-8cb0498936e4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Simon Charette

unread,
Apr 9, 2019, 9:13:19 AM4/9/19
to Django users
No form validation is implemented for UniqueConstraint(condition) yet as that would require
a non-trivial refactor of how it's performed. It was discussed during the feature development[0].

I'd suggest you override you form or your model's clean() method to perform the validation
yourself until built-in support is added.

Submitting a new Trac ticket so we don't loose track of the issue would also be appreciated.

Cheers,
Simon

Michael Barr

unread,
Jul 15, 2019, 4:11:04 PM7/15/19
to Django users
Yeah, this one just bit me in the Django Admin as well. According to the docs,

Validation of Constraints

In general constraints are not checked during full_clean(), and do not raise ValidationErrors. Rather you’ll get a database integrity error on save()UniqueConstraints are different in this regard, in that they leverage the existing validate_unique() logic, and thus enable two-stage validation. In addition to IntegrityError on save()ValidationError is also raised during model validation when the UniqueConstraint is violated.


However, it makes no mention of UniqueConstraint instances with conditions being ignored. It took me diving into the Django source code to find out what was happening. Thankfully, I stumbled upon this here to confirm my sanity. :)

Derek

unread,
Jul 17, 2019, 2:15:52 AM7/17/19
to Django users
Would it be correct to say that adding validation at model clean level would make more sense when using this feature with the admin?

Michael Barr

unread,
Jul 17, 2019, 10:52:38 AM7/17/19
to Django users
That's what I had to revert to doing, yes. I added logic to the validate_unique() method on the model itself and then updated the query logic manually.
Reply all
Reply to author
Forward
0 new messages