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'))

В любом случае, ваше требование о том, что предмет должен быть уменьшен только в соответствии с последним сделанным резервированием, означает, что вам нужно немного проявить творческий подход к тому, как вы просматриваете резервирования. Один из вариантов - упорядочить набор запросов по идентификатору элемента, и каждый раз, когда идентификатор "меняется", корректировать доступную сумму на основе последнего резервирования этого элемента.

Другие вопросы по тегам