Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django';s Model.save()修改不需要的列_Python_Sql_Django - Fatal编程技术网

Python Django';s Model.save()修改不需要的列

Python Django';s Model.save()修改不需要的列,python,sql,django,Python,Sql,Django,最近,我发现Django ORM的Model.save()执行一个SQL来默认更新'ALL'列,即使没有修改任何内容。 这确实让我担心,因为我所做的任何更改都有可能被其他Model.save()过程设置回原始值 例如,我有一个型号订单。有两个并发进程(P1,P2)在处理它。首先,P1选择一行: # P1 order = Order.objects.get(pk=10000) 然后,P2选择同一行并更新状态列:(以下语句可以封装在事务中,甚至可以封装在可序列化的事务中,但这无法解决问题。) 之后

最近,我发现Django ORM的
Model.save()
执行一个SQL来默认更新'ALL'列,即使没有修改任何内容。 这确实让我担心,因为我所做的任何更改都有可能被其他
Model.save()过程设置回原始值

例如,我有一个型号
订单
。有两个并发进程(P1,P2)在处理它。首先,P1选择一行:

# P1
order = Order.objects.get(pk=10000)
然后,P2选择同一行并更新
状态
列:(以下语句可以封装在事务中,甚至可以封装在可序列化的事务中,但这无法解决问题。)

之后,P1更新其他一些琐碎的列:

# P1
order.xxx = xxx    # update some other trivial column
order.save()    # This would set the `status` back to UNPAID !!!
订单。状态
将被设置回
未付款
,这不是我想要的

我知道我可以使用
save(update_fields=…)
选择_for_update()
过滤器(…).update(…)
,可序列化事务,或在P1上显式锁定来防止此问题。 但问题是:在整个项目中的所有
Model.save()
语句上使用它们是荒谬的。此外,即使我在我的项目代码中这样做,也有一些其他代码在这样做(Django Admin、ModelForm…)

我是否应该重写
Model.save()
以仅更新那些修改过的字段


(对我来说,这似乎是一个严重的问题。还是我做错了什么?

正如其他人在评论中所说的,你有一种经典的类型。在Django有一些方法可以解决这个问题。你已经提到了其中一些,但根据我的经验,它们不能被认为是安全的。我强烈建议您观看名为
Immutable Django
,并开始朝这个方向挖掘


基本上,您可以在模型中添加某种类型的
version
列,并在每次保存时增加该列,并与现有列进行比较。如果新版本相同或更少,则已保存一个-您正在尝试保存非实际条目。

您只需要一列即可发生类似的竞争条件:

# Process 1
account = Account.objects.get(pk=1)
account.balance += 1000

# Process 2
account = Account.objects.get(pk=1)
account.balance -= 10
account.save()

# Process 1
account.save()

现在,流程2的余额扣减已丢失。您必须使用
select\u for\u update
确保写入一致。即使只保存“脏”字段,并将其设为默认值,这种情况仍然会发生。

之所以发生,是因为
P1
不知道您更改了
P2
状态
属性。为什么需要两个不同的引用来引用相同的
顺序
?@DeepSpace我认为
P1
P2
是不同的进程。@DeepSpace是的,它们是不同的进程。例如,一名员工正在使用Django Admin修改该订单(
P1
),一名客户正在付款(
P2
)。因此,这是一个竞争条件,但您已经说明了解决此问题的各种方法。
# Process 1
account = Account.objects.get(pk=1)
account.balance += 1000

# Process 2
account = Account.objects.get(pk=1)
account.balance -= 10
account.save()

# Process 1
account.save()