Django - использует выражение F(), но получает не атомарное обновление
У меня есть действие администратора, которое выглядит так:
def process(modeladmin, request, queryset):
for reservation in queryset:
if not reservation.processed:
reservation.processed = True
reservation.save()
item = reservation.item
item.available = F('available') - reservation.quantity
item.save()
Таким образом, администратор может обработать reservation
из item
, Всякий раз, когда он делает, reservation
помечается как обработанный, а количество доступных items
уменьшается на количество, указанное в reservation
,
Как это происходит для всех действий администратора, администратор может обрабатывать несколько reservations
вовремя. Все идет хорошо, если reservations
у всех разные items
, Но если два reservations
поделиться одним item
, количество доступных items
уменьшается только на сумму, указанную в последнем reservation
обработанный.
я думал так F()
выражения были только для этого случая: я хочу внести много изменений в item
и пусть они увеличивают или уменьшают атрибут item
не сталкиваясь с условиями гонки. Что мне не хватает?
2 ответа
Это не совсем то, как вы используете объект F. Как только вы отделяете шаги извлечения от сохранения, вы по сути делаете это явно неатомарным.
Вы должны использовать update
для этого, поэтому элемент должен быть:
Item.objects.filter(id=reservation.item.id).update(available=F('available')-reservation.quantity)
Или что-то подобное.
Выражения F() предназначены для использования в запросе, например, когда вы хотите сделать это в SQL:
SELECT * FROM foo WHERE foo_col = bar_col
Вы бы сделали:
Foo.objects.filter(foo_col=F('bar_col'))
В любом случае, ваше требование о том, что предмет должен быть уменьшен только в соответствии с последним сделанным резервированием, означает, что вам нужно немного проявить творческий подход к тому, как вы просматриваете резервирования. Один из вариантов - упорядочить набор запросов по идентификатору элемента, и каждый раз, когда идентификатор "меняется", корректировать доступную сумму на основе последнего резервирования этого элемента.