我对这些模型有疑问:
class Post(models.Model):
#Some fields ....
class LikePost(models.Model):
# Author info
author = models.ForeignKey(User,related_name='post_likes')
post = models.ForeignKey(Post, related_name="likes")
dateJoined = models.DateTimeField(auto_now_add=True)
当我检索帖子的信息时,我还需要知道当前用户(request.user
)是否已经在当前帖子上做了likeAction。
当我查看帖子的详细信息时,我会使用单个查询有效地(如果可能)这样做。
目前我使用此查询:
Post.objects.annotate(likes_count=Count('likes')).get(pk=pk)
我使用.annotate()
来检索喜欢的数量......
我可以添加关于.annotate()
或.extra()
的内容,以了解用户是否已在当前帖子上制作了likeAction吗?
答案 0 :(得分:0)
这可能是个问题。
根据我的经验,Django ORM最多会将任何特定的表连接到查询中一次。这对于将多个条件应用于相同的相关数据非常有用(这通常非常有用)。你需要的是一些相关数据的两个独立连接;一个你计算所有喜欢的东西,另一个你只关心特定用户喜欢的东西。 Django会做的只是计算特定用户的喜欢,如果你做了像
这样的事情Posts.objects.filter(likes__user_id=user.id).annotate(
likes_count=Count('likes')).get(pk=pk)
如果用户不喜欢特定DoesNotExist
,则会冒Post
例外的风险。如果用户确实喜欢特定帖子likes_count
,则只计算特定用户与特定帖子之间的类似关系的数量。我相信这不是你需要的。
但是,您可以在一个查询中完成所有这些操作,但是您将加载比其他要求更多的数据;
post = Posts.objects.select_related('likes').get(pk=pk)
post.likes_count = len(post.likes)
user_already_likes_this = any(like.user_id == user.id for like in post.likes)
现在,您必须对额外数据方法和两种查询方法进行基准测试。
我确信您应该只使用两种查询方法,因为每个http请求可能已经导致15个或更多查询,因此一个额外的不会造成太大的伤害,并且随着喜欢的数量的增加它会更好地扩展增长。
答案 1 :(得分:0)
result = (Post.objects.annotate(likes_count=Count('likes'))
.extra(
select={
'already_liked': (
"select count(*) from {app_name}_likepost "
"where {app_name}_likepost.author_id = {uid} "
"and {app_name}_likepost.post_id = {pid}"
).format(
uid=request.user.id,
pid=pk,
app_name=your_django_app_name,
),
}
)
.get(pk=pk)
)
result.already_liked # 1 if action performed, 0 if not
但是,这将是子查询,并且某些数据库可能不支持此。 同样django docs建议尽可能避免这种做法。虽然要在一个查询中获取所有需要的数据,但您需要这样做(或手动构建完整的SQL查询)。
正如django docs所述,select_related
不会在后向foreign_key关系上工作,而prefetch_related
实际上会再做一次查询,所以总共会有两个查询(除此之外)那 - 它会加载更多不需要的数据,就像所有LikePost记录一样。)