如何在Django Model Admin中减少关联模型的重复查询次数
解决方案
核心优化思路是复用同个Model1实例对应的最新Model2查询结果,避免同个实例重复查询多次:
方案1:实例属性缓存(总查询次数10次,完全符合要求)
将查询最新Model2的逻辑抽为独立方法,把结果缓存到当前Model1实例的私有属性上,4个字段方法复用该缓存结果,单页10条数据只会产生10次查询。
修改后的Admin代码如下:
@admin.register(Model1) class Model1Admin(admin.ModelAdmin): list_per_page = 10 list_display = ['some_model1_fields', 'get_field1','get_field2', 'get_field3', 'get_field4'] # 私有方法:缓存同个Model1对应的最新Model2实例 def _get_latest_model2(self, obj): if not hasattr(obj, '_cached_latest_model2'): obj._cached_latest_model2 = obj.model2_set.last() return obj._cached_latest_model2 def get_field1(self, obj): latest_model2 = self._get_latest_model2(obj) return latest_model2.field1 if latest_model2 else None def get_field2(self, obj): latest_model2 = self._get_latest_model2(obj) return latest_model2.field2 if latest_model2 else None def get_field3(self, obj): latest_model2 = self._get_latest_model2(obj) return latest_model2.field3 if latest_model2 else None def get_field4(self, obj): latest_model2 = self._get_latest_model2(obj) return latest_model2.field4 if latest_model2 else None
代码同时增加了空值兼容逻辑,避免部分Model1无关联Model2时触发属性不存在报错。
方案2:Prefetch批量预取(总查询次数仅2次,无JOIN关联性能问题)
如果你可以接受额外一次批量查询,可使用Django的prefetch_related进一步优化,该方案是做两次独立的单表查询,不会触发你担心的JOIN关联Count耗时问题:
from django.db import models @admin.register(Model1) class Model1Admin(admin.ModelAdmin): list_per_page = 10 list_display = ['some_model1_fields', 'get_field1','get_field2', 'get_field3', 'get_field4'] def get_queryset(self, request): qs = super().get_queryset(request) # 预取每个Model1对应的最新Model2,仅一次额外查询 return qs.prefetch_related( models.Prefetch( 'model2_set', # 排序逻辑和原last()保持一致即可,这里默认按主键倒序 queryset=Model2.objects.order_by('-pk'), to_attr='_prefetched_latest_model2' ) ) def _get_latest_model2(self, obj): if not hasattr(obj, '_cached_latest_model2'): obj._cached_latest_model2 = obj._prefetched_latest_model2[0] if obj._prefetched_latest_model2 else None return obj._cached_latest_model2 # 后续get_field1~get_field4方法和方案1完全一致,此处省略重复代码
内容的提问来源于stack exchange,提问作者Md Shahbaz Ahmad
相关产品推荐
相关产品推荐

