使用相关对象的外键预取或注释Django模型

时间:2018-07-13 03:01:58

标签: django prefetch

假设我们有以下模型:

class Author(Model):
    ...
class Serie(Model):
    ...
class Book(Model):
    authors = ManyToManyField(Author, related_name="books")
    serie = ForeignKey(Serie)
    ...

如何获取作者列表及其系列?

我尝试了annotateprefetch的不同组合:


list_authors = Author.objects.prefetch(Prefetch("books__series", queryset=Serie.objects.all(), to_attr="series"))

尝试使用list_authors[0].series会引发异常,因为Author没有series字段


list_authors = Author.objects.annotate(series=FilteredExpression("books__series", condition=Q(...))

尝试使用list_authors[0].series会引发异常,因为Author没有series字段


list_authors = Author.objects.annotate(series=F('books__series'))

返回所有拥有共同书籍的(作者,意甲)所有可能组合


当我在数据库中使用PostgreSQL时,我尝试了:

from django.contrib.postgres.aggregates import ArrayAgg
...
list_authors = Author.objects.annotate(series=ArrayAgg('books__serie', distinct=True, filter=Q(...)))

它工作正常,但仅返回相关对象的id

list_authors = Author.objects.annotate(series=ArrayAgg(
    Subquery(
        Serie.objects.filter(
            livres__auteurs=OuterRef('pk'),
            ...
        ).prefetch_related(...)
    )
 ))

失败,因为它需要一个output_field,并且Model对于output_field来说不是有效值

但是 我可以获得作者的系列数,所以为什么不列出它们的实际列表:

list_authors = Author.objects.annotate(nb_series=Count("books__series", filter=Q(...), distinct=True)
list_authors[0].nb_series
>>> 2

因此,我认为我可以做的事情是可能的,但是我对“如何做”感到茫然……

1 个答案:

答案 0 :(得分:1)

我认为您无法在Author查询集上添加注释,因为您已经发现可以执行F('books__series'),但是不会返回不同的结果。通常,仅当结果为每行一个值时,注释才有意义。

您可以做的是在Author模型上有一个方法,可以通过一个相对简单的查询为该作者获取所有系列。这将意味着每位作者另外一个查询,但是我看不到任何其他选择。像这样:

class Author:

    def get_series(self):
        return Serie.objects.filter(book__authors=self).distinct()

那你就做:

list_authors = Author.objects.all()
list_authors[0].get_series()