2016-04-18 3 views
1

Ich bin ein Dropdown mit Werten bevölkern in meinem models.py definiert, so etwas wie:Wie kann ich eine Django-Abfrage für eine benutzerdefinierte Werteliste anfordern?

rank_choices = (
     ('King', 'King') 
     ('Prince', 'Prince') 
     ('Duke', 'Duke') 
     ('Baron', 'Baron') 
     ('Lackey', 'Lackey') 

Wenn ich zu einer bestimmten Zeit eine Liste von Personen mit einem Rang anzeigt, ich möchte, dass sie in erscheinen absteigender Rang.

Aktuelle Abfrage (nur alphabetisch):

attendees = Rank.objects.filter(feast__id=feast__id).exclude(rank='Lackey').order_by('rank') 

Wie kann ich das ändern Rang durch seine Position in der Liste zu bestellen?

Ich erwäge dies:

rank_choices = (
     (0, 'King') 
     (1, 'Prince') 
     (2, 'Duke') 
     (3, 'Baron') 
     (4, 'Lackey') 

Aber selbst wenn ich die ausführlichen Werte wieder aus den numerischen Werten erhalten kann, wird alle Änderungen in der Reihenfolge vor der Änderung falsche Werte für Daten zurückkehren würden. Gibt es einen besseren Weg?

Lösung gewählt

von wim Antwort inspiriert, ich beendete eine Datenmigration bis machen die Reihen, um numerische Werte zu ändern und Sortierung wie folgt.

ranks = sorted(ranks, key=lambda x: int(x.rank)) 

Ich erhalte die ausführlichen Werte zurück, indem sie die rank_choices von meinen Modellen in meine Ansichten zu importieren und die numerischen Werte mit dem entsprechenden Titel nach der Sortierung zu ersetzen.

Antwort

2

Es sieht so aus, als ob Sie rank in einer CharField-Datenbank gespeichert haben. Es ist nicht einfach, eine benutzerdefinierte order_by auszuführen, ohne das Schema zu ändern. Daher ist für einfache Fälle, können Sie prüfen, die Reihenfolge in Python-Code zu machen:

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) 

Nach dem Aufruf von sorted, die queryset ausgewertet werden, und Sie werden stattdessen eine Python-Liste haben.

Ist dies nicht zufrieden stellend ist, ist es möglich (aber nicht recht) in der Django ORM das Ergebnis, das Sie in einem queryset wollen zu erhalten, indem ein Case/When Konstrukt:

>>> 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>] 

Dank user " mu ist zu kurz "in der comments für die Inspiration dieser Idee. Dies wird in Django 1.8+ wegen der neuen Funktionen in conditional expressions funktionieren.

Für Benutzer, die Pech haben, auf älteren Versionen von Django stecken zu bleiben, ist die gleiche Idee möglich, indem ein Raw-Sql-Fragment erstellt wird, das Queryset.extra verwendet.

+0

Danke. Ich werde es versuchen. Ich werde einige andere Attribute des Rank-Objekts und seiner fk-Objekte anzeigen müssen, aber vielleicht kann ich die Flat = 1 weglassen, multiple columns zu values_list geben und damit arbeiten. –

+0

Ja, ändern Sie einfach das Argument, das im sortierten Aufruf an 'key' übergeben wird – wim

+0

Können Sie keinen ORDER BY Ausdruck mit Django angeben? 'Reihenfolge nach Fall Rang, wenn 'König' dann 0, wenn 'Prinz' dann 1 ... Ende 'zum Beispiel. Mit SQL können Sie nach jedem gültigen Ausdruck und nicht nur nach Spalten sortieren. –

Verwandte Themen