Як перейменувати елементи у значеннях () у Django?


101

Я хочу зробити так само, як у цьому квитку на djangoproject.com , але з деяким додатковим форматуванням. З цього запиту

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

Я хочу отримати щось подібне:

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

Чи є інший, більш вбудований спосіб чи я повинен це робити вручну?

Відповіді:


72

Це трохи хакі, але ви можете використовувати extraметод:

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

Це в основному відбувається SELECT cryptic_value_name AS renamed_valueв SQL.

Інший варіант, якщо ви завжди хочете, щоб перейменована версія, але db має криптовану назву, - назвати своє поле новим іменем, але використовувати db_columnдля позначення оригінального імені в db.


6
Мабуть у 1.7. * Ви зможете просто писати псевдонімні імена прямо як іменовані аргументи values(). Джерело: code.djangoproject.com/ticket/16735
gregoltsov

19
-1 тому, що .values(supports__through_tables)цей хак не працює (до речі, мабуть, найбільш очевидний випадок використання для перейменування ValuesQuerySetключів dict)
wim

1
Хтось знайшов спосіб зробити це за допомогою таблиць (.values ​​(supports__through_tables))?
Франсуа Констант

12
На жаль, це рішення не підтримує пов'язані імена, як у .values('foreignkeymodel__id', 'foreignkeymodel__name').
Risadinha

13
Model.objects.annotate (my_alias = F ( 'some__long__name__to__alias')) значення ( 'my_alias') від квитка 16735 ..
Юджині

188

З нього django>=1.8можна використовувати анотацію та об'єкт F

from django.db.models import F

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

Також extra()буде застаріле з документів django:

Це старий API, який ми прагнемо знищити в якийсь момент у майбутньому. Використовуйте його, лише якщо ви не можете висловити запит, використовуючи інші методи набору запитів. Якщо вам потрібно використовувати його, будь ласка, подайте квиток за допомогою ключового слова QuerySet.extra зі своїм випадком використання (спочатку перевірте список існуючих квитків), щоб ми могли покращити API QuerySet, щоб дозволити видалення додаткового (). Ми більше не вдосконалюємо та не виправляємо помилки за цим методом.


3
Ця відповідь працює лише далі django>=1.8. Запроси виразів дозволяють annotateприймати вирази, відмінні від агрегатів. Довідка: docs.djangoproject.com/en/1.9/releases/1.8/…
Єо

3
Це працює, але чи не синтаксис, запропонований в оригінальному питанні, настільки приємний ? MyModel.objects.values(renamed_value='cryptic_value_name')
Вім

11
MyModel.objects.values(renamed_value=models.F('cryptic_value_name'))твори
жарко вугілля

1
Ця відповідь працює, але є зайвою. Аргументи ключових слів, передані для передачі values(), передаються annotate()від вашого імені (див. Docs.djangoproject.com/en/2.2/ref/models/querysets/… ). Відповідь MyModel.objects.values(renamed_value=F('cryptic_value_name'))простіший і зрозуміліший, ІМО.
tobias.mcnulty

76

Без використання будь-якого іншого методу менеджера (перевірено на v3.0.4):

from django.db.models import F

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

Витяг із документів Django :

Об'єкт F () представляє значення модельного поля або стовпця з примітками. Це дозволяє звертатися до модельних значень поля та виконувати операції з базою даних, використовуючи їх, фактично не виймаючи їх із бази даних в пам'ять Python.


5
Для більш ніж одного значення ви можете використовувати:MyModel.objects.values(renamed_value=F('cryptic_value_name'),renamed_value2=F('cryptic_value_name2'))
alpere

1
але що робити, якщо ви хочете змінити одне значення, а інше зберегти ? З анотацією це можливо: inv.annotate(name=F('stock__name')).values('name', "price")але я не бачу, як цей метод повинен працювати в такому випадку. inv.values(name=F("stock__name"), price=F("price"))-> Анотація «ціна» суперечить полі на моделі
Мальте

1
@Malte Я думаю, що тут не потрібно ускладнювати це. Просто спробуйте inv.values('price', name=F("stock__name")). У python ви можете ставити аргументи з іменем лише після неназваних.
Арпіт Сінгх

0

Я працюю з django 1.11.6

(І ключ: пара значень протилежна прийнятій відповіді)

Ось так я змушую це працювати над своїм проектом

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

Зауважте, що додавання одночасних об’єктів.filter (). Extra (). Значень () таке ж, як вище.


ви бачите, що .extra(select={cryptic_value:ranamed_value})має протилежний ключ: значення порівняно з прийнятою відповіддю
Судіп Бхаттарай

-6

Це більш ніж просто, якщо ви хочете перейменувати кілька полів режиму.

Спробуйте

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

Тут у мене немає nameполя в таблиці, але я можу це отримати після того, як трішки переробити.


10
–1 він оцінює набір запитів, який є порушником угод
wim
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.