Метод select_for_update
Метод select_for_update применяется к QuerySet и возвращает новый QuerySet,
строки которого будут заблокированы до конца транзакции. Это необходимо
в ситуациях, когда несколько пользователей или процессов могут одновременно
изменять одни и те же данные. Метод поддерживает параметры
nowait и skip_locked для управления поведением при
конфликтах блокировок.
Синтаксис
Model.objects.select_for_update(nowait=False, skip_locked=False, of=(), no_key=False)
Пример
Заблокируем запись пользователя для обновления баланса внутри транзакции:
from django.db import transaction
from myapp.models import User
with transaction.atomic():
user = User.objects.select_for_update().get(id=1)
user.balance += 100
user.save()
Результат выполнения кода:
"Balance updated successfully"
Пример
Используем параметр nowait чтобы не ждать освобождения заблокированной строки:
from django.db import transaction
from myapp.models import Order
try:
with transaction.atomic():
order = Order.objects.select_for_update(nowait=True).get(id=5)
order.status = 'processed'
order.save()
except Exception as e:
print(f"Order is locked: {e}")
Результат выполнения кода:
"Order is locked: could not obtain lock"
Пример
Применяем блокировку к конкретным таблицам с помощью параметра of:
from django.db import transaction
from myapp.models import Article, Category
with transaction.atomic():
articles = Article.objects.select_for_update(
of=('self', 'category')
).filter(status='draft')
for article in articles:
article.status = 'published'
article.save()
Результат выполнения кода:
"Articles updated with locks on related categories"