#36128: IntegrityError in admin Inline with many-to-many intermediary model
-------------------------------------+-------------------------------------
Reporter: Guillaume LEBRETON | Type:
| Uncategorized
Status: new | Component:
| Documentation
Version: 5.1 | Severity: Normal
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Following this doc section
https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#working-with-
many-to-many-intermediary-models
I set an admin tabular inline with an intermediary model.
The provided example is working but does not make that much sense; can a
person have a membership to the same group several times ? Probably not,
and if you try to do this with a simple many to many inline, without an
intermediary model, you will get a validation error on the admin
interface, "Please correct the duplicate data for group.".
The solution for the intermediary model is then adding a unique
constraint, to avoid duplicated membership. But then, instead of having a
validation error, there is a server error "IntegrityError".
To make the example work with the unique constraint, i had to add a custom
formset:
`models.py`
{{{
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through="Membership")
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
class Meta:
constraints = [
models.UniqueConstraint("person", "group",
name="unique_person_group"),
]
}}}
`admins.py`
{{{
class MembersFormset(forms.models.BaseInlineFormSet):
def clean(self):
groups = []
for form in self.forms:
if form.cleaned_data:
groups.append((form.cleaned_data['group'],
form.cleaned_data['person']))
duplicated_groups = [x for x in groups if groups.count(x) > 1]
if duplicated_groups:
raise ValidationError(
'Duplicated values: %(duplicates)s',
params={'duplicates': ", ".join(group.__str__() for group
in set(duplicated_groups))}
)
class MembershipInline(admin.TabularInline):
model = Membership
extra = 1
formset = MembersFormset
}}}
The doc https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#working-
with-many-to-many-intermediary-models about inline with intermediary model
is quite detailed, but completely lacks hints about UniqueConstraint,
while I think most of the time intermediary m2m are designed with a
UniqueConstraint.
Therefore, documentation should be updated to hint about the recommended
steps to validate unique constraints in Inlines with intermediary m2m.
--
Ticket URL: <https://code.djangoproject.com/ticket/36128>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/django-updates/010701949307df8e-2b441fa4-0ef6-43ff-9668-c6b44ce0a701-000000%40eu-central-1.amazonses.com.