25

我有 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

在 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

3 回答 3

32

You cannot use F, but you can use Subquery and 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)
)
于 2018-05-28T08:06:00.787 回答
18

注意:我的答案现在已经过时了,Django 1.11引入了 OuterRef 它实现了这个特性。检查安德烈贝伦达的答案。

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

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

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

另外,根据这个问题,这是设计使然,近期内没有改变它的计划:

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

于 2016-04-21T09:46:15.467 回答
0
rows = Product.objects.filter(old_field__isnull=False)
for row in rows:
     row.new_field = row.old_field.subfield
Product.objects.bulk_update(rows, ['new_field'])
于 2020-06-19T21:27:14.703 回答