首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何根据自定义的值列表排序Django查询?

如何根据自定义的值列表排序Django查询?
EN

Stack Overflow用户
提问于 2016-04-18 20:22:21
回答 1查看 1.7K关注 0票数 1

我正在用models.py中定义的值填充下拉列表,如下所示:

代码语言:javascript
运行
复制
    rank_choices = (
        ('King', 'King')
        ('Prince', 'Prince')
        ('Duke', 'Duke')
        ('Baron', 'Baron')
        ('Lackey', 'Lackey')

当我在一个特定的时间显示一个有等级的人的列表时,我希望他们出现在降序中。

当前查询(仅按字母顺序):

代码语言:javascript
运行
复制
attendees = Rank.objects.filter(feast__id=feast__id).exclude(rank='Lackey').order_by('rank')

我怎样才能根据它在列表中的位置来改变它的排名呢?

我在考虑这个:

代码语言:javascript
运行
复制
    rank_choices = (
        (0, 'King')
        (1, 'Prince')
        (2, 'Duke')
        (3, 'Baron')
        (4, 'Lackey')

但是,即使我可以从数值中取回冗长的值,排序中的任何更改也会返回数据更改前的不正确值。有更好的办法吗?

选择解

受wim答案的启发,我最后进行了数据迁移,将排名更改为数字值,并按如下方式排序。

代码语言:javascript
运行
复制
ranks = sorted(ranks, key=lambda x: int(x.rank))

通过将模型中的rank_choices导入到我的视图中,并在排序后用相应的标题替换数字值,我将获得详细的值。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-18 20:41:07

看起来您将rank存储在数据库中的CharField中。在不更改模式的情况下执行自定义order_by并不简单。因此,对于简单的情况,可以考虑在python代码中进行排序:

代码语言:javascript
运行
复制
rank_lookup = {rank: n for n,(rank,rank) in enumerate(rank_choices[::-1])}
ranks = Rank.objects.filter(...).values_list('rank', flat=1)
ranks = sorted(ranks, key=rank_lookup.get)

调用sorted之后,将对queryset进行计算,您将得到一个python列表。

如果这不令人满意,则在Django ORM中可以(但不是很漂亮)通过使用Case/When构造在查询集中获得所需的结果:

代码语言:javascript
运行
复制
>>> for rank, rank in rank_choices:
...     Rank.objects.create(rank=rank)
...     
>>> Rank.objects.order_by('rank')  # alphabetical
[<Rank: Baron>, <Rank: Duke>, <Rank: King>, <Rank: Lackey>, <Rank: Prince>]
>>> rank_lookup = {rank: n for n,(rank,rank) in enumerate(rank_choices)}
>>> cases = [When(rank=rank, then=Value(rank_lookup[rank])) for rank in rank_lookup]
>>> cases
[<When: WHEN <Q: (AND: ('rank', 'King'))> THEN Value(0)>,
 <When: WHEN <Q: (AND: ('rank', 'Lackey'))> THEN Value(4)>,
 <When: WHEN <Q: (AND: ('rank', 'Baron'))> THEN Value(3)>,
 <When: WHEN <Q: (AND: ('rank', 'Prince'))> THEN Value(1)>,
 <When: WHEN <Q: (AND: ('rank', 'Duke'))> THEN Value(2)>]
>>>
>>> Rank.objects.annotate(my_order=Case(*cases, output_field=IntegerField())).order_by('my_order')
[<Rank: King>, <Rank: Prince>, <Rank: Duke>, <Rank: Baron>, <Rank: Lackey>]
>>> Rank.objects.annotate(my_order=Case(*cases, output_field=IntegerField())).order_by('-my_order')
[<Rank: Lackey>, <Rank: Baron>, <Rank: Duke>, <Rank: Prince>, <Rank: King>]

由于用户"mu太短“在评论中激发了这一想法。这将在Django 1.8+中工作,因为条件表达式中有新的特性。

对于那些不幸被困在较早版本Django上的用户来说,通过构建一个使用Queryset.extra传递的原始sql片段,同样的想法是可能的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36703590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档