检查Django F Expression中的约束

时间:2015-10-05 21:52:17

标签: django django-models

我有一个定义了字段的Django模型:

contacts = models.PositiveIntegerField(default=0)

... 再往下我试图使用F()表达式对字段进行减量:

self.contacts = models.F("contacts") - quantity

如果不引入竞争条件,我如何检查contacts - quantity是否为负值?

1 个答案:

答案 0 :(得分:1)

你想避免竞争条件。 F()个对象只是其中的第一步。

您在交易中要做的第一件事就是获取您正在更改的行的锁定。这可以防止您在写入数据库时​​读取过时的值。这可以通过更新行来完成,这将阻止行进一步更新,直到提交或回滚事务为止:

with transaction.atomic():
    obj.contacts = F('contacts') - quantity

当您拥有锁定并完成更新时,请检查数据完整性是否仍然完好(即联系人数量不低于0)。如果是,则继续,否则,通过引发异常来回滚事务:

obj.refresh_from_db()
if obj.contacts < 0:
    raise ValueError("Capacity exceeded")

如果剩下足够的联系人,此时您将退出atomic()块,提交事务,其他请求可以获取锁并尝试更新该值。如果没有足够的联系人,事务将被回滚,其他请求永远不会知道值已经改变,因为他们一直在等待锁定。

现在,把它们放在一起:

from django.db import transaction
from django.db.models import F

def update_contacts(obj, quantity):
    with transaction.atomic():
        obj.contacts = F('contacts') - quantity
        obj.save()
        obj.refresh_from_db()
        if obj.contacts < 0:
            raise ValueError("Not enough contacts.")

(注意:obj.refresh_from_db()需要1.8,否则只需使用MyModel.objects.get(pk=obj.pk)。)