Python 如何预取计数并使用它在Django ORM中注释查询集

Python 如何预取计数并使用它在Django ORM中注释查询集,python,sql,django,orm,Python,Sql,Django,Orm,我正在尝试执行高级SQL查询,但不知道如何执行。 我的目标是为一个论坛实现一个读/未读系统,因此我有以下模型(不适用于: 简洁性) 我认为这是不言自明的:主题可以标记为已读。用户对每个主题没有或只有一个ReadActivity。(事实上论坛也是可读的,但这超出了这个问题的范围) 所以:我希望能够获取一个论坛列表,并为每个论坛确定它是已读还是未读(对于给定用户) 我的做法是: 对于每个论坛,如果任何主题没有任何ReadActivity或ReadActivity,其中read_直到

我正在尝试执行高级SQL查询,但不知道如何执行。 我的目标是为一个论坛实现一个读/未读系统,因此我有以下模型(不适用于: 简洁性)

我认为这是不言自明的:主题可以标记为已读。用户对每个主题没有或只有一个ReadActivity。(事实上论坛也是可读的,但这超出了这个问题的范围)

所以:我希望能够获取一个论坛列表,并为每个论坛确定它是已读还是未读(对于给定用户) 我的做法是: 对于每个论坛,如果任何主题没有任何ReadActivity或ReadActivity,其中read_直到 说到SQL,我将通过以下方式实现这一点:

SELECT COUNT("forums_topic"."id")
FROM "forums_topic"
  LEFT JOIN "reads_readactivity"
    ON ("forums_topic"."id" = "reads_readactivity"."object_id" AND "reads_readactivity"."content_type_id" = '11')
WHERE (("reads_readactivity"."id" IS NULL
        OR ("reads_readactivity"."reader_id" = '1' AND "reads_readactivity"."read_until" < "forums_topic”."last_message_date"))
       AND "forums_topic"."forum_id" IN ('1', '2'))
GROUP BY "forums_topic"."forum_id"
但是这个解决方案还不够好,因为我无法选择COUNT(),或者限制为1个结果,并按论坛对计数进行分组

我尝试将此解决方案与annotate结合使用:

queryset = queryset.annotate(is_unread=Count('topics__read_activities’))
但这根本不起作用,它涉及所有的话题

然后我尝试在case/when中使用annotate:

queryset = queryset.annotate(is_unread=Case(
    When(topics=None, then=False),
    When(topics__read_activities=None, then=True),
    When(topics__read_activities__reader=self.request.user, topics__read_activities__read_until__lte=F('topics__created_at'), then=True),
    default=False,
    output_field=BooleanField()
))
但它并没有给出正确的结果。此外,我不确定这是最好的解决方案。我不确定SQL是如何实现的,但如果它在每个主题上都进行内部迭代,这可能太昂贵了

现在我正在考虑编写RawSQL,但是我不知道如何添加一个管理器方法,它可以让我们执行类似于:Forums.objects.filter()。with_unread(),因为我不知道如何访问过滤后的论坛来构建类似的查询 “论坛主题”('1','2')中的“论坛id”) 来自经理本人

也许我错过了什么,也许你知道怎么做。任何帮助都将不胜感激,谢谢

queryset = queryset.annotate(is_unread=Count('topics__read_activities’))
queryset = queryset.annotate(is_unread=Case(
    When(topics=None, then=False),
    When(topics__read_activities=None, then=True),
    When(topics__read_activities__reader=self.request.user, topics__read_activities__read_until__lte=F('topics__created_at'), then=True),
    default=False,
    output_field=BooleanField()
))