Как переопределить поле формы по умолчанию для поля внешних ключей только для чтения в Django ModelAdmin?

Я переопределяю стандартное поле формы внешних ключей на ModelAdmins, как описано здесь. Однако я не переопределяю его, чтобы вернуть подмножество, а вместо этого откладываю поля, чтобы оптимизировать производительность. Например:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "car":
            kwargs["queryset"] = Car.objects.only("name")
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

Это работает для большинства моих случаев, но проблема возникает, когда внешний ключ установлен как поле только для чтения. Во время отладки я заметил, что когда он установлен как read only, поле никогда не передается через метод formfield_for_foreignkey и запрос, извлекающий внешний ключ, выбирает все поля, а не только необходимые. В моем случае, некоторые из полей слишком велики, что приводит к ненужной ужасной производительности.

Я также попробовал второй метод, описанный в документации, используя ModelForm.__init__(), но он не очень полезен для моего случая использования.

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

Поскольку иностранный ключ только для чтения на странице Django Admin отображается как ссылка, я сделал следующее:

from django.utils.html import format_html
from django.urls import reverse

class MyModelAdmin(admin.ModelAdmin):
    @admin.display(description="Car")
    def link_to_car(self, obj):
        link = reverse("admin:appname_car_change", args=[obj.car_id])
        return format_html('<a href="{}">{}</a>'.format(link, Car.objects.all().only("name").get(id=obj.car_id)))

    fields = ("link_to_car")
    readonly_fields = ("link_to_car")

Ну, как я уже сказал, это не связано и не решает проблему переопределения поля формы внешнего ключа, о чем я спрашивал в вопросе, но достигает того же результата, показывая то же самое, сохраняя оптимизацию запроса.

Единственная проблема, с которой я столкнулся, это то, что мне пришлось написать это в уродливой форме Car.objects.all().only("name").get(id=obj.car_id), так как простое написание obj.car.name инициировало бы дополнительный запрос, выбирающий все из Car.

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