【问题标题】:Django update table using data from another tableDjango 使用另一个表中的数据更新表
【发布时间】:2023-03-25 21:58:01
【问题描述】:

我有 2 个表 productscatagories 通过外键连接。 我需要使用字段catagories.price_markup 更新字段products.new_cost,如下所示:

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'))

【问题讨论】:

    标签: django django-orm django-database


    【解决方案1】:

    你不能使用 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)
    )
    

    【讨论】:

    • 据我了解这两个模型之间的关系,我建议成本查询过滤器类似于 id=OuterRef('category_id')
    • 仅作记录,这在 Django 1.7 中是不可能的
    • 如果主键在被引用的表上而不是目标上怎么办?
    • @jbodily 您可以像这样使用 Product.objects.update(new_cost=Subquery(Category.objects.values_list('price_marup')[:1])) 但是所有产品都将具有相同的 new_cost
    【解决方案2】:

    注意:我的答案现在已经过时了,Django 1.11 introduced OuterRef 实现了这个功能。检查 Andrey Berenda 的答案。

    根据documentation,不支持使用join子句的更新,见:

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

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

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

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

    【讨论】:

    • 是的,你是对的,但是解决方案是存在的,请看下面我的回答
    • @AndreyBerenda 我的答案早于 Django 1.11,但我认为它对于坚持使用 Django 1.11 的人仍然有效,我将编辑答案以将其指向我们的答案,谢谢。
    • 如果您使用的是较旧的 Django,那么 (a) 您应该升级,但是 (b) 您可以使用反向端口 django-subquery:pypi.org/project/django-subquery
    【解决方案3】:
    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'])
    

    【讨论】:

      猜你喜欢
      • 2019-12-27
      • 2012-04-07
      • 1970-01-01
      • 2011-06-29
      • 1970-01-01
      • 2012-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多