优化Django查询集相关的比较

时间:2016-05-08 18:35:49

标签: django django-models django-views

我有一个Django应用程序,用户上传照片,并在其下留下评论。反映这些对象的数据模型分别为PhotoPhotoComment

第三个数据模型叫PhotoThreadSubscription。每当用户在照片下发表评论时,用户通过在PhotoThreadSubscription中创建对象来订阅该特定线程。这样,他/她可以随后被其他用户通知在同一线程中留下的评论。

class PhotoThreadSubscription(models.Model):
    viewer = models.ForeignKey(User)
    viewed_at = models.DateTimeField(db_index=True)
    which_photo = models.ForeignKey(Photo)

每当用户在照片下发表评论时,我都会更新该特定照片的用户viewed_at对象的PhotoThreadSubscription属性。因此,其他用户对该特定帖子的提交时间大于viewed_at的任何评论 new

假设我有一个评论的查询集,都属于从不重复的独特照片。我想遍历此查询集并找到最新看不见的评论

目前,我正在以沉重的数据库方式尝试这一点:

latest_unseen_comment = PhotoComment(id=1) #i.e. a very old comment
for comment in comments:
    if comment.submitted_on > PhotoThreadSubscription.objects.get(viewer=user, which_photo_id=comment.which_photo_id).viewed_at and comment.submitted_on > latest_unseen_comment.submitted_on:
        latest_unseen_comment = comment

这显然不是一个很好的方法。首先,我不想在for循环中进行DB调用。如何在一个电话中管理上述内容?具体来说,如何在一次调用中获取相关的PhotoThreadSubscription查询集,接下来,如何使用它来计算 max_unseen_comment ?我现在非常困惑。

class Photo(models.Model):
    owner = models.ForeignKey(User)
    image_file = models.ImageField(upload_to=upload_photo_to_location, storage=OverwriteStorage())
    upload_time = models.DateTimeField(auto_now_add=True, db_index=True)
    latest_comment = models.ForeignKey(blank=True, null=True, on_delete=models.CASCADE)


class PhotoComment(models.Model):
    which_photo = models.ForeignKey(Photo)
    text = models.TextField(validators=[MaxLengthValidator(250)])
    submitted_by = models.ForeignKey(User)
    submitted_on = models.DateTimeField(auto_now_add=True)

如果问题看起来模糊,请询问澄清。

1 个答案:

答案 0 :(得分:2)

我认为这将在一个查询中完成:

latest_unseen_comment = (
    comments.filter(which_photo__photothreadsubscription__viewer=user,
                    which_photo__photothreadsubscription__viewed_at__lt=F("submitted_on"))
            .order_by("-submitted_on")
            .first()
)

这里的关键是使用F expressions,以便可以对每个评论的个别日期进行比较,而不是使用查询中硬编码的单个日期。在将查询集过滤为仅包含未见的注释后,我们会order_by注释的日期并获取第一个。