Django Admin外键作列表列是否会每行触发额外数据库查询?
问题结论
- 你当前的配置一定会触发N+1次数据库查询:Django会先执行1次查询拉取所有Book列表数据,之后遍历每一行Book记录时,都会单独发起1次查询获取关联的Author数据,列表有多少条Book数据,就会多产生多少次查询。
- Django Admin不会自动做关联查询优化,所有关联字段的预加载都需要你手动配置。
- 关联层级到2层及以上时,默认表现和单层关联一致:未配置预加载的前提下,每一层关联访问都会触发额外的单独查询。
优化方案
单层外键关联优化
针对你当前的场景,只需要在BookAdmin中增加list_select_related配置即可,Django会自动用JOIN语句一次性查询出关联的Author数据,避免N+1问题:
class BookAdmin(ModelAdmin): list_display = ('title', 'author_name') # 新增这一行,指定需要预加载的外键字段 list_select_related = ('author',) def author_name(self, obj): # 注意你的Author模型定义的字段是first_name,这里写name会报错 return obj.author.first_name
多层关联优化
如果是2层及以上的外键/一对一正向关联,比如你需要访问obj.author.country.name(Author关联了Country模型),只需要把多层关联路径也加到list_select_related即可:
list_select_related = ('author', 'author__country')
Django会自动做多表JOIN,一次性拉取所有层级的关联数据,不会产生额外查询。
如果是反向外键、多对多类型的关联,你可以通过重写get_queryset方法配置prefetch_related实现预加载:
class BookAdmin(ModelAdmin): list_display = ('title', 'author_name', 'tag_list') def get_queryset(self, request): return super().get_queryset(request).prefetch_related('tags') def tag_list(self, obj): return ", ".join(tag.name for tag in obj.tags.all())
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

