我将覆盖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)
它适用于我的大多数用例,但当外键设置为只读字段时,问题就会出现。在调试过程中,我注意到当它被设置为只读时,该字段永远不会通过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")
好吧,正如我所说,它并不能解决我在问题中所问的重写外键的formfield的问题,但它实现了相同的结果,在保持查询优化的同时显示了相同的内容。
我遇到的唯一问题是必须以一种丑陋的方式Car.objects.all().only("name").get(id=obj.car_id)
编写它,因为简单地编写obj.car.name
会启动一个额外的查询,从Car中选择所有内容。