Сумма связанных объектов по 2 FK в одну таблицу с условиями - PullRequest
2 голосов
/ 23 мая 2019

У меня есть две модели:

class User(Model):
    ...

class Message(Model):
    sender = ForeignKey(User, CASCADE, 'sent_msgs')
    receiver = ForeignKey(User, CASCADE, 'rcvd_msgs')
    ignored = BooleanField()

Я пытаюсь аннотировать набор запросов пользователей общей суммой связанных сообщений, т. Е. Суммой sent_msgs и rcvd_msgs.Кроме того, любое Сообщение с ignored=True следует игнорировать.

Я могу сделать это с помощью RawSQL довольно просто, используя подзапрос:

SELECT COUNT("messages_message"."id")
FROM "messages_message"
WHERE "messages_message"."ignored" = FALSE
  AND (
    "messages_message"."sender_id" = "users_user"."id"
    OR
    "messages_message"."receiver_id" = "users_user"."id"
  )
queryset = queryset.annotate(msgs_count=RawSQL(that_query_above))

Есть ли способсделать это без использования RawSQL?

1 Ответ

2 голосов
/ 23 мая 2019

Мы можем использовать Subquery [Django-doc] здесь:

from django.db.models import Count, OuterRef, Subquery, Q

User.objects.annotate(
    <b>msgs_count=</b>Subquery(
        Message.objects.filter(
            Q(sender_id=OuterRef('pk')) | Q(receiver_id=OuterRef('pk')),
            ignored=False
        ).order_by().values('ignored').annotate(cn=Count('*')).values('cn')
    )
)

Затем создается запрос, подобный:

SELECT auth_user.*,
    (
        <b>SELECT COUNT(*) AS cn</b>
        FROM message U0
        WHERE (U0.sender_id = auth_user.id OR U0.receiver_id = auth_user.id)
            AND U0.ignored = False)
        GROUP BY U0.ignored
    ) <b>AS msgs_count</b>
FROM auth_user
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...