我的Django模型是这样的:
class User(models.Model):
username = models.CharField(max_length=32)
class Message(models.Model):
content = models.TextField()
class UserMessageRel(models.Model):
user = models.ForeignKey(User)
message = models.ForeignKey(Message)
is_read = models.BooleanField()
现在我想获取所有消息,对于每条消息,我需要知道有多少用户已经阅读过它。
天真的做法是:
msgs = Message.objects.all()
messages = []
for msg in msgs:
reads = UserMessageRel.objects.filter(message=msg, is_read=True).count()
messages.append((msg, reads))
但这是非常低效的,使用SQL查询来获取每条消息的读取次数。
我不确定这是否可以在ORM中使用注释或聚合来完成?
我想要的是这样的:
msgs_with_reads = Message.objects.all().annotate(
number_of_reads=Count("user_message_rel_with_is_read_true"))
可以翻译成一个不错的SQL查询。
这可以实现吗?
答案 0 :(得分:2)
我将您的问题解释为您希望缩短此计数的查询时间。不幸的是,使用当前设置,需要进行全表扫描。有一些方法可以改进它,最简单的索引。您可以在UserMessageRel中的Message id列上添加索引,这将加快读取时间(当然,以空间为代价)。但是,访问此计数的最可读方式是彼得的答案。
答案 1 :(得分:1)
你可以从Message对象做一个相关的查找,我会像这样在Message模型上放一个辅助函数,然后你就可以从对象中调用该函数。
def get_read_count(self):
return self.usermessagerel_set.filter(is_read=True).count()
message_obj.get_read_count()
答案 2 :(得分:0)
我没有找到使用Django ORM为我的要求生成一个SQL查询的方法,但以下代码可以生成2个查询:
messages = Message.objects.all()
messageReads = UserMessageRel.objects.filter(isRead=True).
values("message_id").annotate(cnt=Count("user"))
然后我可以使用python中的读取计数来映射消息。 这个解决方案对我来说已经足够了。