繁体   English   中英

Django中注释的奇怪行为

[英]Strange behaviour for annotate in Django

我有两个以下数据库表:

class Story(models.Model):
    user = models.ForeignKey(User)
    date_added = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)
    title = models.CharField(max_length=150)
    description = models.CharField(blank=True, null=True, max_length=2000)
    story_text = models.TextField()

    def __unicode__(self):
        return self.title

class StoryVote(models.Model):
    votes = models.IntegerField()
    story = models.ForeignKey(Story, related_name="votes")

    def __unicode__(self):
        return self.votes

我正在尝试获得5个故事的最高投票数的列表。 我已经阅读了有关聚合的文档,并且使用了annotate功能来获取5个故事的列表,其中包含最多的评论,效果很好,但是当我使用它来计算票数时却不起作用。

这是代码im用于获取投票数最高的5个故事的列表的代码:

most_voted = Story.objects.annotate(num_votes=Count('votes')).order_by('-num_votes')[:5]

这应该根据文档进行,并且我使用了相同的计数注释的方法,但是计数是错误的。

我正在使用以下模板代码:

{% for story in most_voted %}
{{ story.id }}
{{ story.num_votes }}
{% endfor %}

我得到了一个奇怪的结果,这不是我期望的。 我得到了一个故事列表,但是无论故事投票多少票,显示的最高数字都是1 ,如果故事没有任何投票,则显示0 如果我对故事进行多次投票,它仍会在故事上显示数字1 我很困惑,没有人能解释为什么在获取评论列表时它不能正常工作吗?

有关信息,我没有任何问题的注释表如下所示:

class Comment(models.Model):
    user = models.ForeignKey(User)
    date_added = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)
    emailOnReply = models.NullBooleanField(blank=True, null=True)
    comment_text = models.TextField()
    story = models.ForeignKey(Story, related_name="comments")

    def __unicode__(self):
        return self.comment_text

在Python shell中执行此命令时, python manage.py shell

>>> most_voted = Story.objects.annotate(num_votes=Count('votes')).order_by('-num_votes')
>>> for story in most_voted:
...     print story.title + " has " + str(story.num_votes) + " votes."
...
story1 has 1 votes.
story2 has 1 votes.
story3 has 1 votes.
story4 has 0 votes.

实际值如下时:

select * from base_storyvote ;
1|6|2
2|-3|3
3|3|4

上面的ID 1story1 ,显示为1票,但实际上有6票。

您的模型结构令人困惑。 似乎每个故事都有一个StoryVote实例,并且StoryVote的vote字段每次都会增加。 这是一种通常的结构:您通常可以将投票计数保留在Story本身上,或者只为每个投票添加一个新的StoryVote实例,因此就不需要投票计数字段。 在您的情况下,如果您确实确实出于自己的原因希望将模型分开,则可能应该使用OneToOneField而不是外键。

无论如何,注释的作用是计算每个Story的StoryVote实例的数量:但是请注意,该值始终为1。但是在您的情况下,没有理由使用注释,因为只有一个StoryVote:您可以直接访问值:

most_voted = Story.objects.prefetch_related().order_by('-storyvote__votes')
for story in most_voted:
    print story.title + " has " + str(story.votes[0].votes) + " votes."

如果您听取我的建议并使用OneToOne字段,这将更加容易:

most_voted = Story.objects.select_related().order_by('-storyvote__votes')
for story in most_voted:    
    print story.title + " has " + str(story.votes.votes) + " votes."

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM