Opened 8 weeks ago

Closed 3 weeks ago

#35393 closed Bug (fixed)

InlineAdmin's are not possible with an editable UUIDField as primary key.

Reported by: Willem Van Onsem Owned by: Willem Van Onsem
Component: contrib.admin Version: 5.0
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Sarah Boyce)

This issue was reported on StackOverflow: if we have a model with an editable primary key that is not an AutoField, the editing of inlines fails.

This is because then the hidden field to "backlink" to the original item fails: there is no `<input type="hidden" id="id_child_set-0-id" name="child_set-0-id"> in the formsets, so no instances are attached to the forms of the formset. At best this would thus create new instances, at worst, it will in case of the UUID just fail to edit the inline objects and thus reject the entire form(set) and therefore reject the edit of the object in general.

The steps to reproduce these are using models:

class Parent(models.Model):
    name = models.CharField(max_length=128)

class Child(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4)
    name = models.CharField(max_length=128)
    parent = models.ForeignKey(Parent, on_delete=models.CASCADE)

and then work with an admin:

class ChildInline(admin.TabularInline):
    model = Child
    exclude = ("id",)  # important
    extra = 1
    verbose_name = "Subexample"
    show_change_link = True

@admin.register(Parent)
class ParentAdmin(admin.ModelAdmin):
    search_fields = ("name", )
    inlines = [ChildInline,]

An easy workaround is to mark the id field of the Child as editable=False, which will resolve the issue. But it is not said that the UUID should *never* be editable, it is for example possible to exclude that for the inline, but then use it for another ModelAdmin, perhaps to duplicate to another UUID, or just use another primary key field altogether.

The fix turned out to be quite minimal: just ensure that the primary key field is added, so in the helpers.py, for the InlineAdminForm, we use:

    def needs_explicit_pk_field(self):
        return (
            # Auto fields are editable, so check for auto or non-editable pk.
            self.form._meta.model._meta.auto_field
            or not self.form._meta.model._meta.pk.editable
            or self.form._meta.model._meta.pk.name in (self.form._meta.exclude or ())
            or
            # Also search any parents for an auto field. (The pk info is
            # propagated to child models so that does not need to be checked
            # in parents.)
            any(
                parent._meta.auto_field or not parent._meta.model._meta.pk.editable
                for parent in self.form._meta.model._meta.get_parent_list()
            )
        )

Attachments (1)

django-helpers-fix.patch (1015 bytes ) - added by Willem Van Onsem 8 weeks ago.

Download all attachments as: .zip

Change History (5)

by Willem Van Onsem, 8 weeks ago

Attachment: django-helpers-fix.patch added

comment:1 by Sarah Boyce, 7 weeks ago

Description: modified (diff)
Needs tests: set
Owner: changed from nobody to Willem Van Onsem
Status: newassigned
Summary: InlineAdmin's are *not* possible with an *editable* UUIDField as primary key.InlineAdmin's are not possible with an editable UUIDField as primary key.
Triage Stage: UnreviewedAccepted

Thank you for the report Willem!
Replicated on main and can see your patch resolves the issue (thank you for providing that). This just needs a test to be accepted 👍

comment:2 by Sarah Boyce, 5 weeks ago

Needs tests: unset

comment:3 by Sarah Boyce, 3 weeks ago

Triage Stage: AcceptedReady for checkin

comment:4 by Sarah Boyce <42296566+sarahboyce@…>, 3 weeks ago

Resolution: fixed
Status: assignedclosed

In 2995aeab:

Fixed #35393 -- Added excluded pk as a hidden field to the inline admin.

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