Пользовательские первичные ключи нарушают логику инлайнов в админке Django

У меня есть модель с отношением к себе в 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) 

и модели администратора Django:

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)

На сайте администратора я вижу основную модель и инлайн, как и в любом другом случае. Проблема начинается после добавления первого объекта Inline. После его добавления я больше не могу удалить или изменить его. Единственная ошибка, которую я вижу, это "Пожалуйста, исправьте ошибку ниже." без каких-либо проблем ниже. Также нет никаких проблем в логах Django. Я использую Django==5.0.2

Прочитав о похожих проблемах, я обнаружил, что настроенный PK нарушает логику, но на самом деле не нашел никаких обходных путей для решения этой проблемы.

Похоже, что встроенные формы Django не очень хорошо обрабатывают exclude для первичных ключей. Мне удалось воспроизвести это поведение.

Но, хорошая новость в том, что мы можем решить эту проблему, пометив первичный ключ как editable=False [Django-doc], что фактически означает, что эти поля не редактируются в ModelForm, или, по крайней мере, без явного добавления. Это имеет смысл для UUIDField, который является первичным ключом, поскольку вы позволяете системе определять UUID, а не пользователю: это также было (я думаю) причиной, по которой вы выбрали exclude = ('uid',). По какой-то причине это не очень хорошо работает, но мы можем просто сделать это на уровне модели:

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.

Вернуться на верх