我正在使用models.py中定义的值填充下拉列表,例如:
rank_choices = (
('King', 'King')
('Prince', 'Prince')
('Duke', 'Duke')
('Baron', 'Baron')
('Lackey', 'Lackey')
当我显示特定时间排名的人员列表时,我希望他们以降序排名。
当前查询(仅按字母顺序排列):
attendees = Rank.objects.filter(feast__id=feast__id).exclude(rank='Lackey').order_by('rank')
如何根据列表中的位置更改此顺序?
我正在考虑这个:
rank_choices = (
(0, 'King')
(1, 'Prince')
(2, 'Duke')
(3, 'Baron')
(4, 'Lackey')
但即使我可以从数值中获取详细值,排序中的任何更改都会返回不正确的数据预更改值。还有更好的方法吗?
选择解决方案
受到wim的回答的启发,我最终进行了数据迁移,将排名更改为数值并按如下方式进行排序。
ranks = sorted(ranks, key=lambda x: int(x.rank))
我通过将我的模型中的rank_choices导入到我的视图中并在排序后用相应的标题替换数值来获取详细值。
答案 0 :(得分:2)
看起来你有rank
存储在数据库中的CharField中。在不更改架构的情况下执行自定义order_by并不简单。因此,对于简单的情况,您可以考虑在python代码中进行排序:
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
之后,将评估查询集,您将拥有一个python列表。
如果这不令人满意,Django ORM中可能(但不是很漂亮)可以使用Case
/ When
构造在查询集中获得所需的结果:
>>> 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>]
感谢comments中的用户“mu太短”以激发这一想法。由于conditional expressions中的新功能,这将适用于Django 1.8+。
对于不幸被困在较旧版本的Django上的用户来说,通过使用Queryset.extra
构建一个原始sql片段来传递相同的想法是可能的。