django - Django 使用多对多关系中的值对查询进行注释
问题描述
遵循 Django 多对多关系的示例:https ://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/
我希望能够在 Django Admin 中显示文章列表视图上的一列,其中包含相关出版物的标题。因此,如果我有一篇a1
有出版物的文章:
Publication(title='Pub 1')
Publication(title='Pub 2')
我想在管理列表视图中看到一列显示"Pub 1, Pub 2"
. 我可以使用 Admin 类上的自定义函数来做到这一点:
class ArticleAdmin(admin.ModelAdmin):
list_display = ['publication_titles']
def publication_titles(self, obj):
return ', '.join([pub.title for pub in obj.publications.all()])
但这是一个 N+1 问题:每个 Article 行将为每个关联的出版物执行一个查询。我在 Django 调试工具栏中看到了这一点,在列表视图中呈现 24 篇文章时,我看到执行的 SQL 查询数量从 9 个查询变为 33 个。
我想也许我可以prefetch_related
在查询集中做:
class ArticleAdmin(admin.ModelAdmin):
list_display = ['publication_titles']
def get_queryset(self, request):
queryset = super().get_queryset(request)
queryset.prefetch_related('publications')
return queryset
def publication_titles(self, obj):
return ', '.join([pub.title for pub in obj.publications.all()])
但这似乎对执行的 SQL 查询数量没有影响。
我以为我可以annotate()
用来注释管理员中使用的查询集,但我正在努力弄清楚如何做到这一点。就像我想做这样的事情:
class ArticleAdmin(admin.ModelAdmin):
list_display = ['publication_titles']
def get_queryset(self, request):
queryset = super().get_queryset(request)
queryset.annotate(publication_titles=<HOW DO I GENERATE THE COLLECTION OF TITLES>)
return queryset
但我并没有摸索我为<HOW DO I GENERATE THE COLLECTION OF TITLES>
.
如何在不增加对数据库的查询次数的情况下获得显示的出版物列表?
解决方案
QuerySet
s 是不可变的,因此这意味着.prefetch_related
创建一个新 QuerySet
的,因此您可以使用:
class ArticleAdmin(admin.ModelAdmin):
list_display = ['publication_titles']
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related('publications')
def publication_titles(self, obj):
return ', '.join([pub.title for pub in obj.publications.all()])
推荐阅读
- javascript - 我将如何通过网络应用程序编译代码?
- java - 对固定长度的字符串进行排序
- sas - 如何在 SAS DI Studio 中创建新的转换类别?
- laravel - 安装 Namecheap 的 PositiveSSL 后禁止 403
- c++ - 如何扩展 integer_sequence?
- rust - 为 JSON 实现 serde::Deserialize 时无法在 fn 项中捕获动态环境
- .htaccess - htaccess 中 301 重定向的通配符 RewriteRule
- django - 在 Django 中完成页面底部的表单后,将用户移动到同一个地方
- visual-studio-code - VSCode:如何执行“快速打开->水平拆分”?
- python - 单击带有 Selenium 的 ComboButton 项