Таблица обновления Django с использованием данных из другой таблицы
У меня есть 2 таблицы products
и catagories
, связанные внешним ключом.
Мне нужно обновить поле products.new_cost
с помощью поля catagories.price_markup
следующим образом:
UPDATE products p
INNER JOIN categories c ON p.category_id = c.id
SET p.new_cost = ROUND(p.pleer_cost * (1 + c.price_markup/100), -1)
WHERE p.update = 1
В SQL это так просто, но как это сделать с помощью Django ORM?
Моя упрощенная попытка не работает Cannot resolve keyword 'category.price_markup' into field.
:
Product.actived.select_related('category').filter(update=1)).update(new_cost=F('pleer_cost') * F('category.price_markup'))
Ответы
Ответ 1
ОБНОВЛЕНИЕ: Кажется, это или не работает или устарело. Учитывая, что я не использовал Django около 6 лет, я рекомендую взглянуть на другие ответы в этом вопросе вместо этого. Я бы хотел, чтобы этот пункт был помечен и удален, если это возможно, поскольку я вполне уверен, что в настоящее время он вводит в заблуждение и больше не действителен (учитывая оценку -10).
Django использует __
(двойное подчеркивание) для связанных полей. Измените этот category.price_markup
на category__price_markup
и вы должны быть в открытом виде.
Ответ 2
Вы не можете использовать F, но вы можете использовать Subquery и OuterRef:
from django.db.models import Subquery, OuterRef
cost = Category.objects.filter(
id=OuterRef('category_id')
).values_list(
'price_markup'
)[:1]
Product.objects.update(
new_cost=Subquery(cost)
)
Ответ 3
Примечание: мой ответ устарел, Django 1.11 представил OuterRef
, который реализует эту функцию. Проверьте ответ андрея Беренды.
Согласно документации, обновления с использованием предложений объединения не поддерживаются, см.:
Однако, в отличие от объектов F() в фильтрах и исключениях, вы не можете вводить объединения при использовании объектов F() в обновлении - вы можете только опорные поля, локальные для обновляемой модели. Если вы попытаетесь представьте соединение с объектом F(), будет вызвано FieldError:
# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))
Кроме того, в соответствии с этой проблемой, это сделано специально, и в ближайшем будущем не планируется ее менять:
Фактическая проблема здесь заключается в том, что объединенные предложения F() не разрешено в выражениях update(). Это по замыслу; поддержка объединений в update() были явно удалены из-за осложнения в их поддержке в общем случае.
Ответ 4
AFAIU может быть обмануто с помощью
for row in ModelName.objects.filter(old_field__isnull=False):
row.new_field = row.old_field.subfield
row.save()
Ответ 5
from django.db import transaction
with transaction.atomic():
for p in Product.objects.select_related('category').filter(update=1)
p.new_cost= p.pleer_cost * p.category.price_markup
p.save()