我有两个模型:
class Post(models.Model):
#some fields
pass
class Vote(models.Model):
post = mdoels.ForeignKey(Post)
value = models.IntegerField()
Votes 的值可以是 1 或 -1(用户可以投票赞成或反对)。
我如何获得按评分排序的帖子列表?
我有两个模型:
class Post(models.Model):
#some fields
pass
class Vote(models.Model):
post = mdoels.ForeignKey(Post)
value = models.IntegerField()
Votes 的值可以是 1 或 -1(用户可以投票赞成或反对)。
我如何获得按评分排序的帖子列表?
您必须使用注释。 https://docs.djangoproject.com/en/dev/topics/db/aggregation/
class Post(models.Model):
name = models.CharField(max_length=20)
class Vote(models.Model):
post = models.ForeignKey(Post)
value = models.IntegerField()
type = models.CharField(max_length=2, choices=(("AW", "Awesomeness"), ("US", "Usefulness")))
然后你需要导入Sum
并且可以得到一个按他们vote_total
喜欢的排序的帖子列表:
from django.db.models import Sum
Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total')
编辑:
这是一个例子。创建多个帖子对象和投票对象
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) for post in posts]
存在。
[(u'post2', 4), (u'post4', -1), (u'post3', -2), (u'post1', None)]
这有一个问题,因为没有帖子的事情最后会发生。由于 django 的Sum
聚合函数将没有条目的总和视为 None,而不是 0。如果您最初给每个帖子一个值为 0(或像 reddit 的系统一样为值 1)的投票,这可以解决,您不会得到 None:例如:
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”替换为您的应用程序的名称以获得正确的数据库表):
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)]
现在每个帖子现在都将有一个vote_total
, 以及对数据库awesome_total
的useful_total
一次查询。比 ORM 有点丑,但仍然非常可读(这就是 Sum 聚合的工作方式。)。您仍然必须为每个类别的选票进行初始投票,以通过出现乱序的“无”。
我认为这应该有效:
Vote.objects.values_list('post', flat=True).order_by('value')
颠倒顺序:
Vote.objects.values_list('post', flat=True).order_by('-value')
更新
由于 post 是ForeignKey
to 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')))