Come rinominare gli elementi in values ​​() in Django?


102

Voglio fare più o meno lo stesso come in questo ticket su djangoproject.com , ma con una formattazione aggiuntiva. Da questa query

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

Voglio ottenere qualcosa del genere:

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

C'è un altro modo più integrato o devo farlo manualmente?

Risposte:


72

È un po 'hacky, ma potresti usare il extrametodo:

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

Questo fondamentalmente fa SELECT cryptic_value_name AS renamed_valuein SQL.

Un'altra opzione, se vuoi sempre la versione rinominata ma il db ha il nome criptico, è quella di nominare il tuo campo con il nuovo nome ma usa db_columnper fare riferimento al nome originale nel db.


6
Apparentemente in 1.7. * Sarai in grado di scrivere nomi con alias direttamente come argomenti con nome values(). Fonte: code.djangoproject.com/ticket/16735
gregoltsov

19
-1 perché .values(supports__through_tables)e questo hack no (incidentalmente probabilmente il caso d'uso più ovvio per voler rinominare le ValuesQuerySetchiavi dict)
wim

1
Qualcuno ha trovato un modo per farlo attraverso le tabelle (.values ​​(supports__through_tables))?
François Constant il

12
Sfortunatamente, questa soluzione non supporta nomi correlati come in .values('foreignkeymodel__id', 'foreignkeymodel__name').
Risadinha

13
Model.objects.annotate (my_alias = F ('some__long__name__to__alias')). Values ​​('my_alias') from the ticket 16735.
eugene

188

Da django>=1.8puoi usare annotate e F object

from django.db.models import F

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

Inoltre extra()sarà deprecato, dalla documentazione di django:

Questa è una vecchia API che miriamo a deprecare in futuro. Usalo solo se non puoi esprimere la tua query usando altri metodi queryset. Se è necessario utilizzarlo, invia un ticket utilizzando la parola chiave QuerySet.extra con il tuo caso d'uso (controlla prima l'elenco dei ticket esistenti) in modo che possiamo migliorare l'API QuerySet per consentire la rimozione di extra (). Non stiamo più migliorando o correggendo bug per questo metodo.


3
Questa risposta funziona solo django>=1.8. Espressioni di query abilitate annotatead accettare espressioni diverse dagli aggregati. Riferimento: docs.djangoproject.com/en/1.9/releases/1.8/…
Yeo

3
Funziona, ma la sintassi proposta nella domanda originale non è molto più gradevole ? MyModel.objects.values(renamed_value='cryptic_value_name')
wim

11
MyModel.objects.values(renamed_value=models.F('cryptic_value_name'))funziona
jarcoal

1
Questa risposta funziona ma è ridondante. Gli argomenti delle parole chiave passati a values()vengono passati annotate()a tuo nome (vedi docs.djangoproject.com/en/2.2/ref/models/querysets/… ). La risposta con MyModel.objects.values(renamed_value=F('cryptic_value_name'))è più semplice e più chiara, IMO.
tobias.mcnulty

76

Senza utilizzare nessun altro metodo di gestione (testato su v3.0.4):

from django.db.models import F

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

Estratto dalla documentazione di Django :

Un oggetto F () rappresenta il valore di un campo modello o di una colonna annotata. Rende possibile fare riferimento ai valori dei campi del modello ed eseguire operazioni sul database utilizzandoli senza doverli estrarre dal database nella memoria Python.


5
Per più di un valore puoi utilizzare:MyModel.objects.values(renamed_value=F('cryptic_value_name'),renamed_value2=F('cryptic_value_name2'))
alpere

1
ma cosa succede se si desidera modificare un valore e mantenere l'altro? Con annotate è possibile: inv.annotate(name=F('stock__name')).values('name', "price")ma non vedo come dovrebbe funzionare questo metodo in quel caso. inv.values(name=F("stock__name"), price=F("price"))-> L'annotazione "prezzo" è in conflitto con un campo sul modello
Malte

1
@Malte penso che non sia necessario complicare questo. Prova e basta inv.values('price', name=F("stock__name")). In Python puoi inserire argomenti con nome solo dopo quelli senza nome.
Arpit Singh,

0

Sto lavorando con django 1.11.6

(E la chiave: la coppia di valori è opposta a quella della risposta accettata)

Ecco come lo sto facendo funzionare per il mio progetto

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

Nota che l'aggiunta simultanea di oggetti.filter (). Extra (). Values ​​() è la stessa di sopra.


puoi vedere che .extra(select={cryptic_value:ranamed_value})ha la chiave opposta: valore rispetto alla risposta accettata
Sudip Bhattarai

-6

È più che semplice se vuoi rinominare alcuni campi della modalità.

Provare

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

Qui non ho un namecampo nella tabella, ma posso ottenerlo dopo aver modificato un po '.


10
-1 valuta il set di query, che è un
rompicapo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.