Search code examples
djangodjango-admindjango-inline-models

Custom primary keys break Django admin inlines logic


I have a model with self relation in models.py:

from uuid import uuid4 from django.db 
import models 


class Example(models.Model): 
    uid = models.UUIDField(primary_key=True, default=uuid4) 
    title = models.CharField(max_length=128) 
    parent = models.ForeignKey("self", related_name="subexamples", blank=True, null=True) 

and Django admin models:

from .models import Example 
from django.contrib import admin 


class ExampleInline(admin.TabularInline): 
    model = Example 
    exclude = ("uid",) 
    extra = 1 
    verbose_name = "Subexample" 
    show_change_link = True 


class ExampleAdmin(admin.ModelAdmin): 
    search_fields = ("title", ) 
    exclude = ("uid",) 
    inlines = [ExampleInline,] 

admin.site.register(Example, ExampleAdmin)

On the admin site I can see the main model and inline like in any other cases. The problem start after adding first Inline object. After it's added I can no longer delete or change it. The only mistake I see is "Please correct the error below." without any problems below. Also no any problems in Django logs. I'm using Django==5.0.2

After reading about similar problems I found that customized PK breaks logic but actually didn't find any workarounds for this problem.


Solution

  • It seems that Django's inline forms don't handle exclude nicely for primary keys. I managed to replicate the behavior.

    But, the good news is, we can resolve this issue, by marking the primary key as editable=False [Django-doc], which actually means that these fields are not editable in a ModelForm, or at least not without explicitly adding it. This makes sense for a UUIDField that is a primary key, since you let the system define the UUID, not the user: this was also (I think), the reason you picked exclude = ('uid',). For some reason that does not work very well, but we can just do this in the model layer:

    class Example(models.Model):
        uid = models.UUIDField(primary_key=True, default=uuid4, editable=False)
        title = models.CharField(max_length=128)
        parent = models.ForeignKey(
            'self', related_name='subexamples', blank=True, null=True
        )

    Update: I have added a ticket [Django-ticket] and created a opened a pull request [GitHub] to resolve this.