python - Django 条件创建
问题描述
Django ORM 是否提供有条件地创建对象的方法?
例如,假设您想使用某种乐观并发控制来插入新对象。
在某个时刻,您知道要在该表中插入的最新对象,并且您只想在此后没有插入新对象的情况下才创建一个新对象。
如果是更新,您可以根据修订号进行过滤:
updated = Account.objects.filter(
id=self.id,
version=self.version,
).update(
balance=balance + amount,
version=self.version + 1,
)
但是,我找不到任何记录在案的方式来为 a create()
or save()
call 提供条件。
我正在寻找可以在 SQL 查询级别应用这些条件的东西,以避免“读取-修改-写入”问题。
解决方案
编辑:这不是Optimistic Lock
尝试。这是对 OP 提供的代码的直接回答。
Django 提供了一种实现条件查询的方法。它还提供了以下update_or_create(defaults=None, **kwargs)
快捷方式:
该
update_or_create
方法尝试根据给定的kwargs
. 如果找到匹配项,它会更新默认字典中传递的字段。默认值中的值可以是 callables。
所以我们可以尝试混合和匹配这两者以重新创建提供的查询:
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_or_create
尝试使用id=self.id
和version=self.version
在数据库中检索对象。
- 找到:对象
balance
和version
字段将相应地使用Case
条件表达式中的值进行更新(请参阅答案的下一部分)。 - 未找到:
id=self.id
将创建具有和的对象,version=self.version
然后更新其balance
和version
字段。
条件查询的细分:
balance
询问:如果对象存在,则
When
表达式的条件将为真,因此该balance
字段将使用以下值更新:# Existing balance # Added amount F('balance') + amount
如果对象被创建,它将作为初始值
balance
接收。amount
version
询问:如果对象存在,则
When
表达式的条件将为真,因此该version
字段将使用以下值更新:# Existing version # Next Version F('version') + 1
如果对象被创建,它将作为初始值接收
version
(self.version
它也可以是默认的初始版本,如1.0.0
)。
笔记:
- 您可能需要为表达式提供
output_field
参数Case
,请看这里。 - 万一(双关语)对什么是表达式以及如何使用它感到好奇
F()
,我在这里有一个问答风格的例子:How to executearithographic operations between Model fields in django
推荐阅读
- arrays - 如何在程序中搜索 Java 中的最高/最低值?
- javascript - 如何在 python 中将 JavaScript 解析为 JSON?
- r - 在 Azure ML 虚拟机中加载 rds 文件时的不同结果
- function - 如何记录 keras 损失函数
- angular - 从 Angular 8 组件获取打开窗口的 url 更改
- python - Pylint:方法可能是基类中的函数
- azure - 通过工作流自动化和 Azure 安全中心警报触发逻辑应用
- bash - Bash - 增加一个变量,直到它可以在另一个变量中找到 + 如果它匹配一个条件
- java - 使用 Maven 的简单注释处理器库项目
- logstash - Grok 模式、日期和时间格式