Wie benenne ich Elemente in values ​​() in Django um?

101

Ich möchte so ziemlich das Gleiche tun wie in diesem Ticket auf djangoproject.com , aber mit einigen zusätzlichen Formatierungen. Aus dieser Abfrage

>>> MyModel.objects.values('cryptic_value_name')
[{'cryptic_value_name': 1}, {'cryptic_value_name': 2}]

Ich möchte so etwas bekommen:

>>> MyModel.objects.values(renamed_value='cryptic_value_name')
[{'renamed_value': 1}, {'renamed_value': 2}]

Gibt es eine andere, besser eingebaute Möglichkeit oder muss ich dies manuell tun?

Martin
quelle

Antworten:

72

Es ist ein bisschen hacky, aber Sie könnten die extraMethode verwenden:

MyModel.objects.extra(
  select={
    'renamed_value': 'cryptic_value_name'
  }
).values(
  'renamed_value'
)

Dies geschieht grundsätzlich SELECT cryptic_value_name AS renamed_valuein der SQL.

Eine andere Option, wenn Sie immer die umbenannte Version möchten, aber die Datenbank den kryptischen Namen hat, besteht darin, Ihr Feld mit dem neuen Namen db_columnzu benennen, aber auf den ursprünglichen Namen in der Datenbank zu verweisen.

Daniel Roseman
quelle
6
Anscheinend können Sie in 1.7. * Nur Alias-Namen direkt als benannte Argumente schreiben values(). Quelle: code.djangoproject.com/ticket/16735
gregoltsov
19
-1 weil .values(supports__through_tables)und dieser Hack nicht (übrigens wahrscheinlich der offensichtlichste Anwendungsfall für den Wunsch, die ValuesQuerySet
Diktatschlüssel
1
Hat jemand einen Weg gefunden, dies über Tabellen (.values ​​(support__through_tables)) zu tun?
François Constant
12
Leider unterstützt diese Lösung keine verwandten Namen wie in .values('foreignkeymodel__id', 'foreignkeymodel__name').
Risadinha
13
Model.objects.annotate (my_alias = F ( 'some__long__name__to__alias')) Werte ( 'my_alias') aus dem Ticket 16735..
eugene
188

Von können django>=1.8Sie Annotate und F-Objekt verwenden

from django.db.models import F

MyModel.objects.annotate(renamed_value=F('cryptic_value_name')).values('renamed_value')

Auch extra()wird aus den Django-Dokumenten veraltet sein :

Dies ist eine alte API, die wir irgendwann in der Zukunft verwerfen wollen. Verwenden Sie es nur, wenn Sie Ihre Abfrage nicht mit anderen Abfragesatzmethoden ausdrücken können. Wenn Sie es benötigen, reichen Sie bitte ein Ticket mit dem Schlüsselwort QuerySet.extra mit Ihrem Anwendungsfall ein (überprüfen Sie zuerst die Liste der vorhandenen Tickets), damit wir die QuerySet-API erweitern können, um das Entfernen von extra () zu ermöglichen. Wir verbessern oder beheben keine Fehler mehr für diese Methode.

alejandrodnm
quelle
3
Diese Antwort funktioniert nur weiter django>=1.8. Abfrageausdrücke aktiviert annotate, um andere Ausdrücke als Aggregate zu akzeptieren. Referenz: docs.djangoproject.com/de/1.9/releases/1.8/…
Yeo
3
Es funktioniert, aber ist die in der ursprünglichen Frage vorgeschlagene Syntax nicht viel besser ? MyModel.objects.values(renamed_value='cryptic_value_name')
wim
11
MyModel.objects.values(renamed_value=models.F('cryptic_value_name'))Werke
Jarcoal
1
Diese Antwort funktioniert, ist aber redundant. An übergebene Schlüsselwortargumente values()werden annotate()in Ihrem Namen weitergeleitet (siehe docs.djangoproject.com/de/2.2/ref/models/querysets/… ). Die Antwort mit MyModel.objects.values(renamed_value=F('cryptic_value_name'))ist einfacher und klarer, IMO.
tobias.mcnulty
76

Ohne Verwendung einer anderen Manager-Methode (getestet am v3.0.4):

from django.db.models import F

MyModel.objects.values(renamed_value=F('cryptic_value_name'))

Auszug aus Django-Dokumenten :

Ein F () -Objekt repräsentiert den Wert eines Modellfelds oder einer mit Anmerkungen versehenen Spalte. Es ermöglicht, auf Modellfeldwerte zu verweisen und Datenbankoperationen mit diesen auszuführen, ohne sie tatsächlich aus der Datenbank in den Python-Speicher ziehen zu müssen.

Arpit Singh
quelle
5
Für mehr als einen Wert können Sie verwenden:MyModel.objects.values(renamed_value=F('cryptic_value_name'),renamed_value2=F('cryptic_value_name2'))
alpere
1
aber was ist, wenn Sie einen Wert ändern und den anderen behalten möchten ? Mit Annotate ist es möglich: inv.annotate(name=F('stock__name')).values('name', "price")aber ich sehe nicht, wie diese Methode in diesem Fall funktionieren soll. inv.values(name=F("stock__name"), price=F("price"))-> Die Anmerkung 'Preis' steht in Konflikt mit einem Feld im Modell
Malte
1
@ Malte Ich denke, es besteht keine Notwendigkeit, dies zu komplizieren. Versuche es einfach inv.values('price', name=F("stock__name")). In Python können Sie benannte Argumente nur nach unbenannten setzen.
Arpit Singh
0

Ich arbeite mit Django 1.11.6

(Und das Schlüssel-Wert-Paar ist dem der akzeptierten Antwort entgegengesetzt.)

So mache ich es für mein Projekt

def json(university):
    address = UniversityAddress.objects.filter(university=university)
    address = address.extra(select={'city__state__country__name': 'country', 'city__state__name': 'state', 'city__name': 'city'})
    address = address.values('country', 'state', "city", 'street', "postal_code").get()
    return address

Beachten Sie, dass das Hinzufügen simultaner Objekte.filter (). Extra (). Values ​​() dasselbe wie oben ist.

Sudip Bhattarai
quelle
Sie können sehen, dass .extra(select={cryptic_value:ranamed_value})hat entgegengesetzten Schlüssel: Wert im Vergleich zu der akzeptierten Antwort
Sudip Bhattarai
-6

Es ist mehr als einfach, wenn Sie einige Felder des Modus umbenennen möchten.

Versuchen

projects = Project.objects.filter()
projects = [{'id': p.id, 'name': '%s (ID:%s)' % (p.department, p.id)} for p in projects]

Hier habe ich kein nameFeld in der Tabelle, aber ich kann das bekommen, nachdem ich ein wenig gezwickt habe.

AJ
quelle
10
–1 es wertet das Queryset aus, das ein Deal-Breaker ist
wim