簡體   English   中英

如何針對自定義值列表訂購Django查詢?

[英]How can I order a Django query against a custom list of values?

我正在用我的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導入到視圖中,並在排序后將數字值替換為相應的標題,可以得到詳細的值。

看來您已將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列表。

如果這不令人滿意,則可以使用Case / When構造在Django ORM中(但不是很漂亮)在查詢集中獲得所需的結果:

>>> 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 is too short”在評論中啟發了這個想法。 由於條件表達式中的新功能,這將在Django 1.8+中有效。

對於不幸不幸被舊版Django卡住的用戶,通過構造一個原始sql片段以使用Queryset.extra進行傳遞,可以實現相同的想法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM