Python Django条件创建
Django ORM是否提供了一种有条件地创建对象的方法 例如,假设您想使用某种乐观并发控制来插入新对象。Python Django条件创建,python,django,django-orm,Python,Django,Django Orm,Django ORM是否提供了一种有条件地创建对象的方法 例如,假设您想使用某种乐观并发控制来插入新对象。 在某个时刻,您知道要插入到该表中的最新对象,并且仅当此后没有插入新对象时才希望创建新对象 如果是更新,您可以根据修订号进行筛选: updated = Account.objects.filter( id=self.id, version=self.version, ).update( balance=balance + amount, version=sel
在某个时刻,您知道要插入到该表中的最新对象,并且仅当此后没有插入新对象时才希望创建新对象 如果是更新,您可以根据修订号进行筛选:
updated = Account.objects.filter(
id=self.id,
version=self.version,
).update(
balance=balance + amount,
version=self.version + 1,
)
但是,我找不到任何文档化的方法来为create()
或save()
调用提供条件
我正在寻找能够在SQL查询级别应用这些条件的东西,以避免“读-修改-写”问题。除了
QuerySet.update
返回受影响的行数Django没有提供任何原语来处理乐观锁定
然而,有一些第三方应用提供了这样的功能
编辑:看起来OP毕竟不是在乐观锁定解决方案之后进行的。编辑:这不是一次
乐观锁定尝试。这是对OP提供的代码的直接回答
Django提供了一种实现方法。它还提供了以下快捷方式:
update\u或\u create
方法尝试根据给定的kwargs
从数据库中获取对象。如果找到匹配项,它将更新默认字典中传递的字段
默认值中的值可以是可调用的
因此,为了重新创建提供的查询,我们可以尝试混合并匹配这两种查询:
obj, created = Account.objects.update_or_create(
id=self.id,
version=self.version,
defaults={
balance: Case(
When(version=self.version, then=F('balance')+amount),
default=amount
),
version: Case(
When(version=self.version, then=F('version')+1),
default=self.version
)
}
)
查询的分类:
update\u或\u create
将尝试检索数据库中id=self.id
和version=self.version
的对象
- 找到:对象的
和余额
字段将使用版本
条件表达式中的值进行相应更新(请参见答案的下一部分)案例
- 未找到:将创建具有
和id=self.id
的对象,然后将更新其version=self.version
和余额
字段版本
条件查询的细分:
余额
查询:
- 如果对象存在,则
表达式的条件将为true,因此When
字段将更新为以下值:balance
# Existing balance # Added amount F('balance') + amount
# Existing version # Next Version F('version') + 1
- 如果对象被创建,它将作为初始
接收余额
值金额
版本
查询:
- 如果对象存在,
表达式的条件将为true,因此When
字段将使用以下值进行更新:version
# Existing balance # Added amount F('balance') + amount
# Existing version # Next Version F('version') + 1
- 如果对象被创建,它将作为初始
接收version
值(也可以是默认初始版本,如self.version
)1.0.0
注:
- 您可能需要为
表达式提供一个大小写
参数,请查看output_字段
- 出于对
表达式是什么以及它是如何使用的好奇(双关语),我这里有一个问答风格的示例:F()
修订版
编号上加上一个唯一的
,那么如果有人已经构建了这样的修订版,那么创建就会失败。这难道不能解决问题吗?例如,如果您有iban,rev,value
,您可以将unique\u约束在一起=(('iban','rev'),)
,那么数据库将强制不存在具有相同iban
和rev
的两行。因此,.create(…)
将失败,因此您可以针对这些约束设置条件。如果您需要更复杂的约束,通常可以在数据库中对这些约束进行编码(例如检查值>0
。我认为在这里使用更新或创建并不合适。乐观锁定的目的是避免覆盖现有条目(例如,在版本不匹配时)不在不匹配时创建新的。@SimonCharette这不是乐观锁定的尝试。这是一个直接的答案,使用实际的OP代码(我可能应该将其编辑到答案中…).你是对的,我错读了OP的问题,因此删除了我的否决票。我以为OP在寻找乐观的锁定解决方案。@SimonCharette没问题。我编辑了我的答案,以反映它直接回答了提供的代码!