首页 > 解决方案 > 以任意顺序对查询集进行排序

问题描述

我有这样一个模板来展示数据库中的块

<div class="panel panel-default">
  <div class="panel-heading">
    <a style='font-size:18pt' href="article/list/{{ b.id }}">{{ b.name }}</a>
    <span class='pull-right'>{{ b.admin }}</span>
  </div>
  <div class="panel-body">
    {{ b.desc }}
  </div>
</div>

数据模型:

class Block(models.Model):
    STATUS = (
        (1,  'normal'),
        (0, 'deleted'),
    )
    name = models.CharField("block name", max_length=100)
    desc = models.CharField("block description", max_length=100)
    admin = models.CharField("block admin", max_length=100)
    status = models.IntegerField(choices=STATUS)

    class Meta:
        ordering = ("id",)

    def __str__(self):
        return self.name   

我检索数据为

In [2]: from article.models import Block
In [3]: blocks = Block.objects.all()
In [4]: blocks
Out[4]: <QuerySet [<Block: Concepts>, <Block: Reading>, <Block: Coding>, <Block: Action>]>

我想以任意顺序 ['concept','code', 'read', 'action']而不是按 id 来呈现数据,

通过观察,我发现这可以通过订购第二个字母来实现,

In [7]: sorted(l, key=lambda item: item[1], reverse=True)
Out[7]: ['concept', 'code', 'read', 'action']

如何以这种方式对查询集进行排序?

标签: pythondjango

解决方案


您可以先注释每个Block实例,然后按使用Substr函数 [Django-doc]的注释进行排序,例如:

from django.db.models.functions import Substr

Block.objects.annotate(
    sndchar=Substr('name', 2, 1)
).order_by('-sndchar')

作为额外奖励,每个Block实例都有一个sndchar属性,该属性是该属性的第二个字符name(仅在此查询集中)。但这不是我认为的真正问题。如果它与另一列冲突,您可以重命名它。

中的减号-sndchar表示我们将按降序排序。如果要按升序排序,可以将其删除。

因此,排序是在数据库级别完成的,这通常(显着)比在 Django 级别执行此操作要快。

您还可以通过删除参数从第二个字符开始对字符串进行排序(例如,在tie的情况下,考虑第三个字符等),length从而使用除第一个字符之外的名称进行注释:

from django.db.models.functions import Substr

# This will sort on the third character in case of a tie, and so on
Block.objects.annotate(
    sndchar=Substr('name', 2)
).order_by('-sndchar')

推荐阅读