根据计算值使用 Django ORM 更新字段
Update field with Django ORM based on computed value
我有一个基本模型:
class MyModel(Model):
id = models.IntegerField()
is_admin = models.BooleanField()
我想实现的是根据id
值是否在某个范围内,一次更新整个table的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。
您可以使用 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)
)
)
P.S。如果你需要很多这种查询,你可以使用下面的自定义表达式(对注释也很有用)。不过要小心,我已经让它为一个查询中断一次,这可能是由于使用了旧版本的 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))
我有一个基本模型:
class MyModel(Model):
id = models.IntegerField()
is_admin = models.BooleanField()
我想实现的是根据id
值是否在某个范围内,一次更新整个table的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。
您可以使用 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)
)
)
P.S。如果你需要很多这种查询,你可以使用下面的自定义表达式(对注释也很有用)。不过要小心,我已经让它为一个查询中断一次,这可能是由于使用了旧版本的 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))