Таблица обновления 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'))

4 ответов


Django использует __ (двойное подчеркивание) для смежных областях. Изменить это category.price_markup до category__price_markup и вы должны быть в ясном.


по словам документация, обновления с использованием предложений join не поддерживаются, см.:

однако, в отличие от объектов F() в предложениях filter и exclude, вы не можете вводить соединения при использовании объектов F() в обновлении – можно только поля ссылок, локальные для обновляемой модели. Если вы попытаетесь введите соединение с объектом F (), будет поднят FieldError:

# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))

также, согласно этому вопрос, это по дизайну и нет никаких планов, чтобы изменить его в ближайшем будущем:

фактическая проблема здесь заключается в том, что присоединенные предложения F() не являются разрешено в инструкциях update (). Это по дизайну; поддержка соединений в update() предложения были явно удалены из-за присущих осложнения в поддержании их в общем случае.


вы не можете использовать F, но вы можете использовать подзапрос и OuterRef:

from django.db.models import Subquery, OuterRef

cost = Category.objects.filter(
    id=OuterRef('product_id')
).values_list(
    'price_markup'
)[:1]

Product.objects.update(
    new_cost=Subquery(cost)
)

AFAIU это может быть workarounded с

for row in ModelName.objects.filter(old_field__isnull=False):
     row.new_field = row.old_field.subfield
     row.save()