#python #django #django-orm
#python #django #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)
Я хочу переключить их numbers ( n
) .
В update
методе моего сериализатора (drf) я пытался
@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.
Комментарии:
1. Не знаю, сработает ли это, но попробуйте использовать
bulk_update
2. Спасибо за подсказку. Я предполагаю, что это сработает, но кажется странным не вызывать
super().update()
и использоватьbulk_update
вместо этого. В любом случае, это единственное решение, о котором я тоже могу подумать.
Ответ №1:
Я не смог решить эту проблему ни с bulk_update
помощью, ни с помощью raw 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)
Единственное решение этой проблемы — сделать столбец обнуляемым и записать 3 раза в таблицу, что причиняет физическую боль.