PAYATHON 2026

如何只在 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 的查询开销。

备注:内容仅供参考。