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

Prefetch or annotate Django model with the foreign key of a related object

假设我们有以下模型:

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'))

returns 具有共同书籍的(作者,系列)的所有可能组合


当我在我的数据库中使用 PostgreSQL 时,我试过:

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

它工作正常,但 returns 只有 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

因此我认为我尝试做的事情是可能的,但我对 "How"...

感到茫然

我不认为你可以用 Author 查询集上的注释来做到这一点 - 因为你已经发现你可以 F('books__series') 但那不会 return 不同结果。通常只有当结果是每行一个值时注释才有意义。

你可以做的是在 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()