Django 查询集:用计算值进行注释

问题描述 投票:0回答:1

我正在为我的网站制作一个非常简单的通知系统,由 Django REST Framework API 提供支持。它用于向所有用户发送网站更新和内容,每个人都会收到相同的通知,然后他们可以将其标记为已读/存档。我想出了以下模型:

class Notification(models.Model):
    title = models.CharField(max_length=255)
    text = models.TextField()
    type = models.CharField(max_length=255, blank=True)
    read_by = models.ManyToManyField(User, blank=True, related_name="read_notifications")
    archived_by = models.ManyToManyField(User, blank=True, related_name="archived_notifications")
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)
    updated_at = models.DateTimeField(auto_now=True)

所以没有接收器字段或类似的东西,因为无论如何所有用户都会收到所有通知。

现在我正在尝试编写视图逻辑,特别是以下两件事:仅获取创建用户后发出的非存档通知,并向其添加计算的“is_read”字段,以不执行额外操作的方式查询每个通知/用户组合。

查询现在看起来像这样:

queryset = Notification.objects
    .order_by("-created_at")
    .filter(created_at__gt=self.request.user.created_at)
    .exclude(archived_by=self.request.user)

这确实按预期过滤掉了存档查询,而且我认为它不需要对每个通知进行额外的查询:

SELECT "notifications_notification"."id", "notifications_notification"."title", "notifications_notification"."text", "notifications_notification"."type", "notifications_notification"."created_at", "notifications_notification"."updated_at" FROM "notifications_notification" WHERE ("notifications_notification"."created_at" > 2022-09-26 12:44:04.771961+00:00 AND NOT (EXISTS(SELECT 1 AS "a" FROM "notifications_notification_archived_by" U1 WHERE (U1."user_id" = 1 AND U1."notification_id" = ("notifications_notification"."id")) LIMIT 1))) ORDER BY "notifications_notification"."created_at" DESC

到目前为止一切顺利!但我仍然需要以某种方式向查询添加“is_read”值(或“is_unread”,如果更容易的话),但我无法弄清楚该怎么做。

如何完成查询并使其高性能?

django django-models
1个回答
0
投票

我想出了这个:

queryset = Notification.objects.order_by("-created_at")
    .filter(created_at__gt=self.request.user.created_at)
    .exclude(archived_by=self.request.user)
    .annotate(is_read=Exists(Notification.objects.filter(pk=OuterRef("id"), read_by=self.request.user)))

这是可行的,尽管它确实执行了两个子查询,我想知道这是否会成为以后的瓶颈?

SELECT "notifications_notification"."id", "notifications_notification"."title", "notifications_notification"."text", "notifications_notification"."type", "notifications_notification"."created_at", "notifications_notification"."updated_at", 
EXISTS(SELECT 1 AS "a" FROM "notifications_notification" U0 INNER JOIN "notifications_notification_read_by" U1 ON (U0."id" = U1."notification_id") 
WHERE (U0."id" = ("notifications_notification"."id") AND U1."user_id" = 1) LIMIT 1) AS "is_read" FROM "notifications_notification" 
WHERE ("notifications_notification"."created_at" > 2022-09-26 14:40:29.368043+00:00 AND NOT (EXISTS(SELECT 1 AS "a" FROM "notifications_notification_archived_by" U1 
WHERE (U1."user_id" = 1 AND U1."notification_id" = ("notifications_notification"."id")) LIMIT 1))) 
ORDER BY "notifications_notification"."created_at" DESC
© www.soinside.com 2019 - 2024. All rights reserved.