Django升序和降序排序

3
假设我想按总票数、浏览量和评论数对“Threads”进行排序。但是它们的“order”模型是从“Thread”模型实例化的。

django oder

这是我的models.py

class Thread(models.Model):
    ....
    rating = RatingField(can_change_vote=True)

    def get_comments(self):
        return Comment.objects.filter(thread__pk=self.pk)

    def get_visitors(self):
        return Visitor.objects.filter(thread__pk=self.pk)

    def get_rating_frequence(self):
        return self.rating.get_difference()

class Comment(models.Model):
    thread = models.ForeignKey(Thread, ...)
    ....

class Visitor(models.Model):
    thread = models.ForeignKey(Thread, ...)
    ....

使用 django updown 来创建 Vote 模型。

更多信息请参见:https://github.com/weluse/django-updown/blob/master/updown/models.py#L20

class Vote(models.Model):
    content_type = models.ForeignKey(ContentType, related_name="updown_votes")
    object_id = models.PositiveIntegerField()
    ....

这是我的 views.py

def threads(request):
    ....
    template_name = 'foo/bar/threads.html'
    threads = Thread.objects.published()

    get_sorted_ratings = request.GET.get('sr', '')
    get_sorted_visitors = request.GET.get('sv', '')
    get_sorted_comments = request.GET.get('sc', '')

    context = {
        'threads': threads,
        ....
    }
    return render(request, template_name, context)

问题是,我如何基于“Thread”模型订购多个模型? 在我的测试中:
>>> from django.db.models import (Q, Count, Sum)
>>> from myapp.models import (Thread, Comment, Visitor)
>>> t = Thread.objects.published()
>>> Visitor.objects.filter(thread__in=t).values('thread').annotate(visit=Count('thread__id')).order_by('-visit')
<QuerySet [{'thread': 3, 'visit': 8}, {'thread': 10, 'visit': 8}, {'thread': 9, 'visit': 7}, {'thread': 48, 'visit': 1}, {'thread': 57, 'visit': 1}, {'thread': 79, 'visit': 1}, {'thread': 103, 'visit': 1}, {'thread': 104, 'visit': 1}, {'thread': 132, 'visit': 1}, {'thread': 178, 'visit': 1}, {'thread': 216, 'visit': 1}, {'thread': 227, 'visit': 1}, {'thread': 267, 'visit': 1}, {'thread': 292, 'visit': 1}, {'thread': 300, 'visit': 1}, {'thread': 305, 'visit': 1}, {'thread': 1201, 'visit': 1}, {'thread': 1252, 'visit': 1}, {'thread': 1265, 'visit': 1}, {'thread': 1929, 'visit': 1}]>
>>> 
>>> Comment.objects.filter(thread__in=t).values('thread').annotate(total=Count('thread__id')).order_by('-total')
<QuerySet [{'total': 9, 'thread': 10}, {'total': 7, 'thread': 9}, {'total': 3, 'thread': 3}, {'total': 3, 'thread': 213}, {'total': 2, 'thread': 35}, {'total': 2, 'thread': 47}, {'total': 2, 'thread': 104}, {'total': 2, 'thread': 187}, {'total': 2, 'thread': 233}, {'total': 2, 'thread': 235}, {'total': 2, 'thread': 304}, {'total': 1, 'thread': 34}, {'total': 1, 'thread': 68}, {'total': 1, 'thread': 82}, {'total': 1, 'thread': 95}, {'total': 1, 'thread': 137}, {'total': 1, 'thread': 216}, {'total': 1, 'thread': 231}, {'total': 1, 'thread': 244}, {'total': 1, 'thread': 253}, '...(remaining elements truncated)...']>
>>> 
>>> # rating likes, id=thread.id, total=total rating
>>> t.values('id').annotate(total=Sum('rating_likes')).order_by('-total')
<QuerySet [{'total': 3, 'id': 10}, {'total': 2, 'id': 104}, {'total': 2, 'id': 233}, {'total': 2, 'id': 235}, {'total': 2, 'id': 304}, {'total': 1, 'id': 3}, {'total': 1, 'id': 9}, {'total': 1, 'id': 34}, {'total': 1, 'id': 35}, {'total': 1, 'id': 47}, {'total': 1, 'id': 68}, {'total': 1, 'id': 82}, {'total': 1, 'id': 95}, {'total': 1, 'id': 137}, {'total': 1, 'id': 187}, {'total': 1, 'id': 213}, {'total': 1, 'id': 216}, {'total': 1, 'id': 231}, {'total': 1, 'id': 244}, {'total': 1, 'id': 253}, '...(remaining elements truncated)...']>
>>> 
>>> # rating dislikes, id=thread.id, total=total rating
>>> t.values('id').annotate(total=Sum('rating_dislikes')).order_by('-total')
<QuerySet [{'total': 2, 'id': 3}, {'total': 1, 'id': 9}, {'total': 1, 'id': 10}, {'total': 1, 'id': 35}, {'total': 1, 'id': 47}, {'total': 1, 'id': 187}, {'total': 0, 'id': 29}, {'total': 0, 'id': 34}, {'total': 0, 'id': 42}, {'total': 0, 'id': 45}, {'total': 0, 'id': 48}, {'total': 0, 'id': 51}, {'total': 0, 'id': 53}, {'total': 0, 'id': 57}, {'total': 0, 'id': 68}, {'total': 0, 'id': 72}, {'total': 0, 'id': 75}, {'total': 0, 'id': 76}, {'total': 0, 'id': 77}, {'total': 0, 'id': 79}, '...(remaining elements truncated)...']>
>>>
>>> Thread.objects.get(pk=3).rating.dislikes
2
>>> Thread.objects.get(pk=9).rating.dislikes
1
>>>

最后,我更新了它:我的代码像@prakhar-trivedi在https://dev59.com/oJ7ha4cB1Zd3GeqPi2nd#41775990中建议的那样工作得很好。

threads = Thread.objects.published()

def sorted_threads(values, order_by='-total', next_order=None):
    """
    return sorted threads from values by `order_by`
    :param `values`, an example:
        values = Comment.objects.filter(thread__in=threads)
                        .values('thread').annotate(total=Count('thread__id'))
    """
    if next_order is not None:
        top_values = values.order_by(order_by).order_by(next_order)
    else:
        top_values = values.order_by(order_by)
    list_pk_threads = [pk['thread'] for pk in top_values]
    filter_threads = list(threads.filter(pk__in=list_pk_threads))
    return sorted(filter_threads, key=lambda i: list_pk_threads.index(i.pk))

要查看完整的内容,请访问gist

但是,我完全不知道如何将它们组合起来。 例如: 按照 votes=1views=1comments=1 进行排序。 并且结果是; 从受欢迎程度按照 votes、按照 views 和按照 comments 排序的 Thread Objects另一个例子: 按照 votes=1 views=1 进行排序。 此条件的输出应该只返回从受欢迎程度按照 votes 和按照 views 排序的 Thread Objects1 表示 True-1 表示 False
1个回答

3
您可以使用 order_by('-thread'),像这样:
Comment.objects.filter(thread__in=t).values('thread').annotate(total=Count('thread__id')).order_by('-thread')

如果您想按照帖子模型的评分对记录进行排序,可以在帖子键上使用双下划线"__"来查找外键,像这样:

# rating likes

Comment.objects.filter(thread__in=t).values('thread').annotate(total=Count('thread__id')).order_by('thread__rating_likes')

根据要求,在所有查询中使用此功能。

仅有两个模型,如果有三个或更多模型怎么办..? 例如,在我的筛选器中从 request.GET.get('sr','')request.GET.get('sv','') 以及 request.GET.get('sc','') 进行排序。 - binpy
@SancaKembang 外键查找与 __ 的使用类似于链接,如果使用正确的语法,它可以被多次使用。 - Prakhar Trivedi
例如,如果线程模型有一个字段评分,它是另一个模型的外键,该模型具有投票计数字段,则可以使用 thread__rating__voteCount - Prakhar Trivedi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接