Python 在django按类似挖掘的评级订购
我有两种型号:Python 在django按类似挖掘的评级订购,python,django,rating-system,Python,Django,Rating System,我有两种型号: class Post(models.Model): #some fields pass class Vote(models.Model): post = mdoels.ForeignKey(Post) value = models.IntegerField() 投票的值可以是1或-1(用户可以向上或向下投票) 我怎样才能得到一个按评级排序的帖子列表?我认为这应该是可行的: Vote.objects.values_list('post', fla
class Post(models.Model):
#some fields
pass
class Vote(models.Model):
post = mdoels.ForeignKey(Post)
value = models.IntegerField()
投票的值可以是1或-1(用户可以向上或向下投票)
我怎样才能得到一个按评级排序的帖子列表?我认为这应该是可行的:
Vote.objects.values_list('post', flat=True).order_by('value')
要颠倒顺序,请执行以下操作:
Vote.objects.values_list('post', flat=True).order_by('-value')
更新
因为post是一个外键
到post
,让我们假设您的模型是这样的:
class Post(models.Model):
post_id = models.AutoField(primary_key=True)
post_name = models.CharField(max_length=30, unique=True)
因此,这应该是可行的,它将返回以下名称:
Vote.objects.values_list('post__post_name', flat=True).order_by('value')
注_
如果要对列表进行查询并出现错误,只需将其转换为列表:
list(Vote.objects.values_list('post__post_name', flat=True).order_by('value')))
您必须使用注释 然后您需要导入
Sum
,并可以获得按其vote\u total
排序的帖子列表,如:
from django.db.models import Sum
Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total')
编辑:这里有一个例子。创建多个post对象和Vote对象
Post.objects.get_or_create(id=1, name="post1")
Post.objects.get_or_create(id=2, name="post2")
Post.objects.get_or_create(id=3, name="post3")
Post.objects.get_or_create(id=4, name="post4")
Vote.objects.get_or_create(id=1, post_id=2, value=1, type="AW")
Vote.objects.get_or_create(id=2, post_id=2, value=1, type="AW")
Vote.objects.get_or_create(id=3, post_id=2, value=1, type="US")
Vote.objects.get_or_create(id=4, post_id=2, value=1, type="US")
Vote.objects.get_or_create(id=5, post_id=3, value=-1, type="AW")
Vote.objects.get_or_create(id=6, post_id=3, value=-1, type="AW")
Vote.objects.get_or_create(id=7, post_id=4, value=-1, type="AW")
然后posts=Post.objects.annotate(vote_total=Sum('vote_value'))。order_by('-vote_total')
将导致[(Post.name,Post.vote_total)对于Post-in-posts]
被删除
[(u'post2', 4), (u'post4', -1), (u'post3', -2), (u'post1', None)]
这有一个问题,因为没有帖子的事情会在最后发生。正如django的Sum
aggregation函数将no条目的和视为None,而不是0。如果您最初给每个帖子一个值为0(或像reddit的系统一样为1)的投票,那么这个问题就可以解决了,您不会得到无:例如:
for p in Post.objects.all():
Vote.objects.get_or_create(post_id=p.id, value=0)
然后你会得到
>>> [(p.name, p.vote_total) for p in
Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total')]
[(u'post2', 4), (u'post1', 0), (u'post4', -1), (u'post3', -2)]
编辑:根据关于不同投票类型的评论,将类型添加到投票模型(如上所述)。 您应该能够执行以下操作(将“yourappname”替换为应用程序的名称以获得正确的db表):
现在,在对数据库的一次查询中,每篇文章都将有一个
投票总数
,以及令人敬畏的总数
和有用的总数
。比ORM更难看一点,但仍然非常可读(这就是总和聚合的工作原理)。你仍然需要给每一类投票一次初始投票,以通过那些没有出现错误的投票。Hmm,这会返回一些奇怪的东西,比如3,1,1,1,1,3,1,3,3,3,3,3,3,3,3,1,3,“…(剩余的元素被截断)…。]我想你误解了这个问题。你只是在排列投票名单,并说出名字是投哪一票。我想要的系统是按投票总数的顺序列出帖子(如我的回答所示)。显然我不明白这一点。但如果你已经提供了一个好答案:)和一个好答案,非常好的解释!哇,谢谢,这是一个很好的解决方案-我应该感到惭愧,我不知道总和聚合函数的存在。顺便说一句,是否有任何方式来过滤总投票数?我的意思是,在实际的项目中,我有不同类型的投票(例如,“awesomness”和“Usability”),我是否可以以某种方式过滤只按特定投票类型排序的相关投票,下面是一个在额外子句中使用SQL SELECT语句仅过滤一种投票类型的示例。非常感谢,你是我的救星:)我想,我应该学习SQL,因为ORM在某些情况下是不够的。@Data贪婪:很高兴得到了大家的帮助。这是django中非常罕见的一种情况,在这种情况下,了解一点SQL有助于超越ORM(并且SQL相当简单且可读)。django文档中也对其进行了详细的记录,参见第二个示例(唯一的区别是它们使用COUNT而不是SUM作为聚合,并且在where子句中没有and):仅供参考,SUM()
的默认值是开放的。
>>> [(p.name, p.vote_total) for p in
Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total')]
[(u'post2', 4), (u'post1', 0), (u'post4', -1), (u'post3', -2)]
select_dict = dict(vote_total = "SELECT SUM(value) FROM yourappname_vote WHERE yourappname_vote.post_id = yourappname_post.id",
awesome_total = "SELECT SUM(value) FROM yourappname_vote WHERE yourappname_vote.post_id = yourappname_post.id AND yourappname_vote.type = 'AW' ",
useful_total = "SELECT SUM(value) FROM yourappname_vote WHERE yourappname_vote.post_id = yourappname_post.id AND yourappname_vote.type = 'US' ",)
posts = Post.objects.all().extra(select = select_dict).order_by('-vote_total')
>>> [(p.name, p.vote_total, p.awesome_total, p.useful_total) for p in posts]
[(u'post2', 4, 2, 2),
(u'post1', 0, 0, 0),
(u'post4', -1, -1, 0),
(u'post3', -2, -2, 0)]