Django - 使用F()表达式但获得非原子更新

时间:2012-05-15 16:28:13

标签: python django django-models race-condition

我的管理操作如下:

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的{​​{1}}。无论何时,item都会被标记为已处理,可用reservation的数量会减少items中指定的数量。

对于所有管理操作,管理员可以一次处理多个reservation。如果reservations具有所有不同的reservations,那么一切顺利。但如果两个items共享一个reservations,则可用item的数量仅会减少上一个items处理中指定的数量。

我认为reservation表达式只适用于这种情况:我希望对F()进行许多更改,并让它们在item上增加或减少属性,而不会遇到竞争条件。我错过了什么?

2 个答案:

答案 0 :(得分:1)

这并不是你如何使用F对象。一旦你将保存的步骤分开,你实际上将其明确地视为非原子。

您应该使用update,因此部分应为:

Item.objects.filter(id=reservation.item.id).update(available=F('available')-reservation.quantity)

或类似的东西。

答案 1 :(得分:-2)

F()表达式用于查询,例如,当您想在SQL中执行此操作时:

SELECT * FROM foo WHERE foo_col = bar_col

你会这样做:

Foo.objects.filter(foo_col=F('bar_col'))

无论如何,您要求的项目只能根据上次预订而减少,这意味着您必须对循环预订的方式有所启发。一个选项是按项目ID排序查询集,每次ID“更改”时,根据该项目的上次预订调整可用金额。