Как переопределить поле формы по умолчанию для поля внешних ключей только для чтения в 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.