Bagaimana mengganti nama item dalam values ​​() di Django?

102

Saya ingin melakukan hal yang sama seperti pada tiket ini di djangoproject.com , tetapi dengan beberapa format tambahan. Dari kueri ini

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

Saya ingin mendapatkan sesuatu seperti itu:

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

Apakah ada cara lain yang lebih builtin atau apakah saya harus melakukan ini secara manual?

Martin
sumber

Jawaban:

72

Agak hacky, tetapi Anda bisa menggunakan extrametode ini:

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

Ini pada dasarnya dilakukan SELECT cryptic_value_name AS renamed_valuedi SQL.

Pilihan lain, jika Anda selalu menginginkan versi yang diganti namanya tetapi db memiliki nama yang samar, adalah memberi nama bidang Anda dengan nama baru tetapi digunakan db_columnuntuk merujuk ke nama asli di db.

Daniel Roseman
sumber
6
Rupanya di 1.7. * Anda hanya bisa menulis nama alias langsung sebagai argumen bernama values(). Sumber: code.djangoproject.com/ticket/16735
gregoltsov
19
-1 karena .values(supports__through_tables)dan peretasan ini tidak (kebetulan mungkin kasus penggunaan yang paling jelas untuk ingin mengganti nama ValuesQuerySetkunci dict)
wim
1
Adakah yang menemukan cara untuk melakukan ini melalui tabel (.values ​​(supporting__through_tables))?
François Constant
12
Sayangnya, solusi ini tidak mendukung nama terkait seperti di .values('foreignkeymodel__id', 'foreignkeymodel__name').
Risadinha
13
Model.objects.annotate (my_alias = F ('some__long__name__to__alias')). Values ​​('my_alias') dari tiket 16735.
eugene
188

Dari django>=1.8Anda dapat menggunakan anotasi dan objek F.

from django.db.models import F

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

Juga extra()akan ditinggalkan, dari dokumen django:

Ini adalah API lama yang ingin kami hentikan di beberapa titik di masa mendatang. Gunakan hanya jika Anda tidak dapat mengekspresikan kueri Anda menggunakan metode queryset lain. Jika Anda memang perlu menggunakannya, harap ajukan tiket menggunakan kata kunci QuerySet.extra dengan kasus penggunaan Anda (harap periksa daftar tiket yang ada terlebih dahulu) sehingga kami dapat menyempurnakan QuerySet API untuk memungkinkan penghapusan ekstra (). Kami tidak lagi meningkatkan atau memperbaiki bug untuk metode ini.

alejandrodnm.dll
sumber
3
Jawaban ini hanya berhasil django>=1.8. Ekspresi Kueri diaktifkan annotateuntuk menerima ekspresi selain agregat. Referensi: docs.djangoproject.com/en/1.9/releases/1.8/…
Yeo
3
Ini berfungsi, tetapi bukankah sintaks yang diusulkan dalam pertanyaan asli jauh lebih baik ? MyModel.objects.values(renamed_value='cryptic_value_name')
wim
11
MyModel.objects.values(renamed_value=models.F('cryptic_value_name'))karya
jarcoal
1
Jawaban ini berfungsi tetapi mubazir. Argumen kata kunci yang diteruskan ke values()diteruskan annotate()atas nama Anda (lihat docs.djangoproject.com/en/2.2/ref/models/querysets/… ). Jawabannya dengan MyModel.objects.values(renamed_value=F('cryptic_value_name'))lebih sederhana dan lebih jelas, IMO.
tobias.mcnulty
76

Tanpa menggunakan metode manajer lain (diuji pada v3.0.4):

from django.db.models import F

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

Kutipan dari dokumen Django :

Sebuah F () objek merupakan nilai dari bidang model yang atau kolom dijelaskan. Itu memungkinkan untuk merujuk ke nilai bidang model dan melakukan operasi database menggunakannya tanpa benar-benar harus menariknya keluar dari database ke memori Python.

Arpit Singh
sumber
5
Untuk lebih dari satu nilai, Anda dapat menggunakan:MyModel.objects.values(renamed_value=F('cryptic_value_name'),renamed_value2=F('cryptic_value_name2'))
alpere
1
tetapi bagaimana jika Anda ingin mengubah satu nilai dan mempertahankan nilai yang lain? Dengan anotasi dimungkinkan: inv.annotate(name=F('stock__name')).values('name', "price")tetapi saya tidak melihat bagaimana metode ini harus bekerja dalam kasus itu. inv.values(name=F("stock__name"), price=F("price"))-> 'Harga' anotasi bertentangan dengan bidang pada model
Malte
1
@Malte Saya rasa tidak perlu mempersulit ini. Coba saja inv.values('price', name=F("stock__name")). Dalam python Anda hanya dapat meletakkan argumen bernama setelah yang tidak disebutkan namanya.
Arpit Singh
0

Saya bekerja dengan django 1.11.6

(Dan kuncinya: pasangan nilai berlawanan dengan jawaban yang diterima)

Beginilah cara saya membuatnya berfungsi untuk proyek saya

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

Perhatikan bahwa menambahkan simultanous object.filter (). Extra (). Values ​​() sama seperti di atas.

Sudip Bhattarai
sumber
Anda dapat melihat bahwa .extra(select={cryptic_value:ranamed_value})memiliki kunci yang berlawanan: nilai dibandingkan dengan jawaban yang diterima
Sudip Bhattarai
-6

Ini lebih dari sederhana jika Anda ingin mengganti nama beberapa bidang mode.

Mencoba

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

Di sini saya tidak memiliki namekolom di tabel, tetapi saya bisa mendapatkannya setelah sedikit mengutak-atik.

AJ
sumber
10
–1 mengevaluasi queryset, yang merupakan pemecah kesepakatan
wim