我正在尝试执行高级SQL查询,但我无法弄清楚如何执行此操作。 我的目标是为论坛实现一个读/未读系统,所以我有以下模型(不完整的: 简洁)
class ReadActivity(models.Model):
content_object = GenericForeignKey('content_type', 'object_id')
reader = models.ForeignKey(User, null=False, blank=False)
read_until = models.DateTimeField(blank=False, null=False, default=timezone.now)
class Meta:
unique_together = (("content_type", "object_id", "reader"),)
class Readable(models.Model):
read_activities = GenericRelation(ReadActivity)
class Meta:
abstract = True
class Forum(models.Model):
pass
class Topic(Readable):
pass
我认为这是非常自我解释的:主题可以标记为已读。用户每个主题具有零个或一个ReadActivity。 (事实上论坛也是可读的,但这个问题超出了这个问题)
所以:我希望能够获取论坛列表,并为每个论坛确定它是读取还是未读取(对于给定用户) 我的方法是: 对于每个论坛,如果任何主题没有任何ReadActivity或ReadActivity,其中read_until< last_message,将论坛标记为未读。
说到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"
但是我找不到使用Django ORM(没有很多查询)的方法。我试图使用Prefetch:
topics_prefetch = Topic.objects.filter(Q(read_activities=None) | (Q(read_activities__reader=self.request.user) & Q(read_activities__read_until__gt=F('created_at'))))
queryset = queryset.prefetch_related(Prefetch('read_activities', queryset=ReadActivity.objects.filter(reader=self.request.user)))
但是这个解决方案还不够好,因为我无法选择COUNT()或限制为1个结果,并按论坛对计数进行分组。
我尝试将此解决方案与注释结合使用:
queryset = queryset.annotate(is_unread=Count('topics__read_activities’))
但这只是不起作用,它会计算所有主题
然后我尝试在case / when:
中使用annotatequeryset = 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()
))
但它没有给出正确的结果。而且我不确定这是最好的解决方案。我不确定如何实现CASE / WHEN SQL,但如果它在内部迭代每个主题,这可能太贵了
现在我正在考虑编写RawSQL,但是我不知道如何添加一个管理器方法,它可以做类似的事情:Forums.objects.filter()。with_unread(),因为我不知道如何访问过滤的论坛以构建一个类似的查询 &#34; forums_topic&#34;&#34; forum_id&#34; IN(&#39; 1&#39;,&#39; 2&#39;)) 来自经理本身。
也许我错过了什么,也许你知道怎么做。任何帮助将不胜感激,谢谢!