如何只在 Django admin change 页面优化 get_queryset?
数据小许
结论
可以在 ModelAdmin.get_queryset(request) 中检查 request.resolver_match.url_name,确认当前请求是否对应这个模型的 change 页面,再对查询集调用 select_related() 或 prefetch_related()。如果需要优化 inline 自身的数据,也要在对应 inline 类的查询集中单独配置预加载。
在 ModelAdmin 中判断 change 页面
Django admin 模型 change 页面的 URL 名称通常由应用名、模型名和 change 后缀组成。可以根据当前 ModelAdmin 的模型信息生成名称,再与 url_name 比较:
from django.contrib import admin
from .models import Order
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
def get_queryset(self, request):
queryset = super().get_queryset(request)
match = request.resolver_match
change_url_name = f"{self.opts.app_label}_{self.opts.model_name}_change"
if match and match.url_name == change_url_name:
queryset = queryset.select_related("customer").prefetch_related("items")
return queryset
将 customer 和 items 替换为 Order 上实际存在的关联字段。select_related() 适用于 ForeignKey 和 OneToOne 关系;prefetch_related() 适用于 ManyToMany 和反向关系。
Inline 数据需要单独优化
OrderAdmin.get_queryset() 优化的是 Order 查询集。如果 change 页面中的自定义 inline 还会加载其他关联对象,可以在 inline 的 get_queryset() 中配置预加载:
class OrderItemInline(admin.TabularInline):
model = OrderItem
def get_queryset(self, request):
queryset = super().get_queryset(request)
return queryset.select_related("product")
这里的 product 应替换为 inline 模型上实际存在的关联字段。主对象和 inline 对象的查询可以分别配置预加载。
注意事项
- 使用精确的 URL 名称比较,可以避免把其他 admin 页面误判为当前模型的 change 页面。
- 正常路由解析后的 admin 请求通常有
request.resolver_match,示例中仍保留了空值检查。 - 预加载关联会增加查询集加载的数据量。应根据 change 页面实际访问的字段配置关联,并留意不同页面和 inline 的查询开销。
备注:内容仅供参考。
