【问题标题】:Update field with Django ORM based on computed value根据计算值使用 Django ORM 更新字段
【发布时间】:2021-06-15 16:13:41
【问题描述】:

我有一个基本模型:

class MyModel(Model):
    id = models.IntegerField()
    is_admin = models.BooleanField()

我想要实现的是根据id 值是否在某个值列表中,一次更新整个表的is_admin 字段的值。

基本上,在原始 SQL 中,这是我想要的查询:

UPDATE my_model
SET is_admin = (id IN (1, 2, 3, 4))

如何使用 Django 的 ORM 实现这一点?

这是我迄今为止尝试过的:

from django.db.models import F, Value


admin_ids = (1, 2, 3, 4)

MyModel.objects.update(is_admin=F("id") in admin_ids)
# Resulting query is:
# UPDATE my_model SET is_admin = false

MyModel.objects.update(is_admin=F("id") in Value(admin_ids))
# TypeError: argument of type 'Value' is not iterable

MyModel.objects.filter(id__in=admin_ids).update(admin=True)
MyModel.objects.exclude(id__in=admin_ids).update(admin=False)
# it works... but can I do this in a single query instead of two?

我正在使用 Django 3.2 和 PostgreSQL。

【问题讨论】:

    标签: python django django-orm


    【解决方案1】:

    您可以使用CASE / WHEN 构造。 https://docs.djangoproject.com/en/3.2/ref/models/conditional-expressions/

    MyModel.objects.update(
        is_admin=Case(
            When(id__in=admin_ids, then=Value(True)),
            default=Value(False)
        )
    )
    
    

    附:如果你需要这种查询很多,你可以使用下面的自定义表达式(对注解也很有用)。虽然要小心,但我已经为一个查询中断了一次,可能是由于使用了旧版本的 Django。在其他项目中,我在生产中使用它没有任何问题。

    class BooleanQ(ExpressionWrapper):
        output_field = BooleanField()
    
        def __init__(self, *args, **kwargs):
            expression = models.Q(*args, **kwargs)
            super().__init__(expression, output_field=None)
    
        def as_sql(self, compiler, connection):
            try:
                return super().as_sql(compiler, connection)
            except EmptyResultSet:
                return compiler.compile(Value(False))
    
    
    MyModel.objects.update(is_admin=BooleanQ(id__in=admin_ids))
      
    

    【讨论】:

    • 完美运行 :) 如果有人建议使用“更漂亮”的方法,我会将这篇文章打开一段时间,但非常感谢您的帮助!
    猜你喜欢
    • 2020-08-08
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 2022-08-18
    相关资源
    最近更新 更多