按 django 中类似挖掘的评级排序

发布于 2024-11-14 06:37:33 字数 249 浏览 5 评论 0原文

我有两个模型:

class Post(models.Model):
    #some fields
    pass

class Vote(models.Model):
    post = mdoels.ForeignKey(Post)
    value = models.IntegerField()

投票值可以是 1 或 -1(用户可以投票赞成或反对)。

我如何获得按评分排序的帖子列表?

I've got two models:

class Post(models.Model):
    #some fields
    pass

class Vote(models.Model):
    post = mdoels.ForeignKey(Post)
    value = models.IntegerField()

Votes' value can be either 1 or -1 (user can vote up or down).

How can i get a list of posts, ordered by their rating?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

城歌 2024-11-21 06:37:33

你必须使用注释。 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),则可以解决这个问题,您将没有得到“无”:例如:

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< /code> 和 useful_total 在一次数据库查询中。比 ORM 丑一点,但仍然具有很强的可读性(这就是 Sum 聚合的工作原理。)。您仍然需要对每个类别的投票进行初始投票,以通过无顺序出现的投票。

You have to use annotation. 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")))

Then you need to import Sum and can get a list of posts ordered by their vote_total like:

from django.db.models import Sum
Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total')

EDIT:
Here's an example. Create several post objects and Vote Objects

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")

Then posts = Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total') will lead to [(post.name, post.vote_total) for post in posts] being.

[(u'post2', 4), (u'post4', -1), (u'post3', -2), (u'post1', None)]

This has an issue as things with no posts go at the very end. As django's Sum aggregation function takes the sum of no entries as None, not 0. This could be solved if you initially gave every post a vote with value 0 (or value 1 like reddit's system), you wouldn't get the None: e.g.:

for p in Post.objects.all():
    Vote.objects.get_or_create(post_id=p.id, value=0)

Then you'll get

>>> [(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)]

EDIT: Added type to the Vote model (done above), per comment about different vote types.
You should be able to do something like (replace 'yourappname' with the name of your application to get the right db table):

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)]

Now each post now will have a vote_total, as well awesome_total and useful_total in one query to the database. A bit uglier than the ORM, but still quite readable (and this is how the Sum aggregation works. ). You still will have to give each category of votes an initial vote to get past the None appearing out of order.

策马西风 2024-11-21 06:37:33

我认为这应该可行:

Vote.objects.values_list('post', flat=True).order_by('value')

要反转顺序:

Vote.objects.values_list('post', flat=True).order_by('-value')

UPDATE

由于 post 是 PostForeignKey ,我们假设您的模型是这样的:

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')))

I think this should work:

Vote.objects.values_list('post', flat=True).order_by('value')

To invert the order:

Vote.objects.values_list('post', flat=True).order_by('-value')

UPDATE

Since post is a ForeignKey to Post, let's assume your model is something like this:

class Post(models.Model):
    post_id = models.AutoField(primary_key=True)
    post_name = models.CharField(max_length=30, unique=True)

So this should work, it would return the names:

 Vote.objects.values_list('post__post_name', flat=True).order_by('value')

note_

If you want to make queries with the list and some error appear, just transform it to a list:

list(Vote.objects.values_list('post__post_name', flat=True).order_by('value')))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文