首页 > 解决方案 > 使用 F 表达式保存两次

问题描述

执行以下代码时。

from django.db.models import F

# assume that stories_filed is 0 at the start. 
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()
reporter.save()

结果是stories_filed等于2。为什么会这样,有没有避免这个错误的好方法。将其包装在事务中会防止该问题吗?

标签: pythondjango

解决方案


F表达式 [Django-doc]是对字段的引用。如果您设置stories_filedF('stories_filed') + 1,那么当您设置为 时.save(),它将进行如下查询:

UPDATE app_reporter
SET stories_filed = stories_filed + 1
WHERE pk = pk-of-object

因此它将增加数据库端的字段。事实上,如果你查询什么reporter.stories_filed是,它会指定这是F('stories_filed') + 1,所以增量逻辑不会在 Django/Python 级别执行。

请注意,如果您.save()是一个对象,则该对象不会从数据库中重新加载,因此第一次之后.save()stories_filed仍然是F('stories_filed') + 1,因此第二次.save()调用将查询另一个增量。

但是,建议对F对象执行此操作,因为存在多个视图更新同一记录的竞争条件,这可能意味着某些增量丢失。事实上,如果两个视图都适用:

reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed += 1
reporter.save()

那么有可能两个视图结束后,该值只增加一次,那是因为它们首先加载相同的记录,它们都将它增加一个,然后它们都保存新值,但是第二个视图将因此保存记录stories_filed从它检索到的记录中递增,并且不考虑其他视图的更新。


推荐阅读