Django аннотировать с related_name из A -> C, где A-> B и B -> C, где '->' - обратная связь - PullRequest
1 голос
/ 18 апреля 2020

Я много искал по inte rnet, но не смог найти похожий вопрос.

У меня есть 3 модели: Domain, Topic, Post Каждая Domain может иметь много Topics и каждый Topic может иметь множество Posts.

Topic имеет foreign key до Domain, а Post имеет foreign key до Topic.

Так что я могу включить count of Posts в Topic на annotate(Count('posts')), и я могу включить count of Topics в Board на annotate(Count('topics'))

Есть ли способ включить count of Posts в Board на annotate?

1 Ответ

1 голос
/ 18 апреля 2020

Да, вы можете использовать двойное подчеркивание (__) для просмотра отношения:

from django.db.models import Count

Domain.objects.annotate(
    <b>num_posts=Count('topics__posts')</b>
)

, если вы объедините это с подсчетом числа Topic s, вам нужно будет добавить distinct=True на Count из Topic с, поскольку это составит два JOIN с, а JOIN на Post с будет действовать как « множитель »:

from django.db.models import Count

Domain.objects.annotate(
    num_posts=Count('topics__posts'),
    num_topics=Count('topics'<b>, distinct=True</b>)
)

Это приведет к следующему запросу:

SELECT domain.*
       COUNT(post.id) AS num_posts
       COUNT(DISTINCT topic.id) AS num_topics
FROM domain
LEFT OUTER JOIN topic ON topic.domain_id = domain.id
LEFT OUTER JOIN post ON post.topic_id = topic.id
GROUP BY domain.id

Если вы опустите distinct=True, то же самое топи c будет считаться несколько раз раз (ровно столько же раз, сколько число сообщений, относящихся к этой теме c), и, следовательно, num_topics должно быть таким же, как num_posts. Используя DISTINCT, мы подсчитываем количество уникальных тем в каждой группе.

...