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?

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.


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.


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.


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.


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.


10
–1 es wertet das Queryset aus, das ein Deal-Breaker ist
wim
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.