【问题标题】:Django annotate query with values from Many To Many RelationshipDjango 使用多对多关系中的值对查询进行注释
【发布时间】:2021-06-24 23:21:06
【问题描述】:

遵循 Django 多对多关系的示例:https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/

我希望能够在 Django 管理中显示文章列表视图上的一列,其中包含相关出版物的标题。所以如果我有一篇文章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 问题:每个文章行都会为每个关联的出版物执行一个查询。我在 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

但我不知道我会为 &lt;HOW DO I GENERATE THE COLLECTION OF TITLES&gt; 设置什么。

如何在不增加对数据库的查询次数的情况下显示出版物列表?

【问题讨论】:

    标签: django django-models django-admin


    【解决方案1】:

    QuerySets 是不可变的,这意味着.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()])
    

    【讨论】:

    • 非常感谢!完美运行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-26
    • 1970-01-01
    • 2013-07-20
    • 2021-03-07
    相关资源
    最近更新 更多