如何在一个事务中执行两个更新语句,这样它们就不会 运行 成为 Django ORM 中的唯一约束?
How to execute two update statements in one transaction so they won't run into unique constraint in Django ORM?
给定模型
from django.db import models
class RelatedTo(models.Model):
pass
class Thing(models.Model):
n = models.IntegerField()
related_to = models.ForeignKey(RelatedTo, on_delete=models.CASCADE)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['n', 'related_to'],
name='unique_n_per_related_to'
)
]
和
>>> r = RelatedTo.objects.create()
>>> thing_zero = Thing.objects.create(related_to=r, n=0)
>>> thing_one = Thing.objects.create(related_to=r, n=1)
我想换号码(n
)。
在我的序列化程序 (drf) 的 update
方法中,我试图
@transaction.atomic
def update(self, instance, validated_data):
old_n = instance.n
new_n = validated_data['n']
Thing.objects.filter(
related_to=instance.related_to,
n=new_n
).update(n=old_n)
return super().update(instance, validated_data)
但它仍然 运行 受到限制。
select_for_update
也无济于事。
是否可以不使用 Django ORM 运行 进入此数据库约束,或者我是否必须 运行 原始 sql 才能实现?
Django==3.1.2
postgres:12.5
错误
duplicate key value violates unique constraint "unique_n_per_related_to"
DETAIL: Key (n, related_to)=(1, 1) already exists.
我无法通过 bulk_update
或原始 sql.
解决此问题
stmt = f"""
update {to_update._meta.db_table} as t
set n = i.n
from (values
('{to_update.id}'::uuid, {n}),
('{method.id}'::uuid, {n})
) as i(id, n)
where t.id = i.id
"""
with connection.cursor() as cur:
cur.execute(stmt)
此问题的唯一解决方案是使该列可为空,并向 table 写入 3 次,这对身体造成伤害。
给定模型
from django.db import models
class RelatedTo(models.Model):
pass
class Thing(models.Model):
n = models.IntegerField()
related_to = models.ForeignKey(RelatedTo, on_delete=models.CASCADE)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['n', 'related_to'],
name='unique_n_per_related_to'
)
]
和
>>> r = RelatedTo.objects.create()
>>> thing_zero = Thing.objects.create(related_to=r, n=0)
>>> thing_one = Thing.objects.create(related_to=r, n=1)
我想换号码(n
)。
在我的序列化程序 (drf) 的 update
方法中,我试图
@transaction.atomic
def update(self, instance, validated_data):
old_n = instance.n
new_n = validated_data['n']
Thing.objects.filter(
related_to=instance.related_to,
n=new_n
).update(n=old_n)
return super().update(instance, validated_data)
但它仍然 运行 受到限制。
select_for_update
也无济于事。
是否可以不使用 Django ORM 运行 进入此数据库约束,或者我是否必须 运行 原始 sql 才能实现?
Django==3.1.2
postgres:12.5
错误
duplicate key value violates unique constraint "unique_n_per_related_to"
DETAIL: Key (n, related_to)=(1, 1) already exists.
我无法通过 bulk_update
或原始 sql.
stmt = f"""
update {to_update._meta.db_table} as t
set n = i.n
from (values
('{to_update.id}'::uuid, {n}),
('{method.id}'::uuid, {n})
) as i(id, n)
where t.id = i.id
"""
with connection.cursor() as cur:
cur.execute(stmt)
此问题的唯一解决方案是使该列可为空,并向 table 写入 3 次,这对身体造成伤害。