Django使用另一个表中的数据更新表

Dea*_*dly 20 django django-orm django-database

我有2个表productscatagories通过外键连接.我需要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
Run Code Online (Sandbox Code Playgroud)

在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'))
Run Code Online (Sandbox Code Playgroud)

And*_*nda 21

你不能使用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)
)
Run Code Online (Sandbox Code Playgroud)


Ces*_*ssa 18

注意:我的答案现在已经过时了,Django 1.11 引入了 OuterRef 它实现了这个功能.检查下面的Andrey Berenda答案.

根据文档,不支持使用join子句的更新,请参阅:

但是,与filter和exclude子句中的F()对象不同,在更新中使用F()对象时不能引入连接 - 您只能引用要更新的模型的本地字段.如果尝试引入带有F()对象的连接,将引发FieldError:

# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))
Run Code Online (Sandbox Code Playgroud)

此外,根据这个问题,这是设计上的,并且没有计划在不久的将来改变它:

这里的实际问题似乎是update()语句中不允许加入F()子句.这是设计的; 由于在一般情况下支持它们的固有复杂性,因此明确删除了对update()子句中的连接的支持.