Django有条件的创造

sam*_*ces 12 python django django-orm

Django ORM是否提供了有条件地创建对象的方法?

例如,假设您希望使用某种乐观并发控制来插入新对象.
在某个时刻,您知道要在该表中插入的最新对象,并且您只想在此后没有插入新对象时才创建新对象.

如果是更新,您可以根据修订号进行过滤:

updated = Account.objects.filter(
    id=self.id,
    version=self.version,
).update(
    balance=balance + amount,
    version=self.version + 1,
)
Run Code Online (Sandbox Code Playgroud)

但是,我找不到任何记录的方式来为a create()save()call 提供条件.

我正在寻找在SQL查询级别应用这些条件的东西,以避免"读 - 修改 - 写"问题.

Joh*_*fis 9

编辑:这不是一次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
        )
    }
)
Run Code Online (Sandbox Code Playgroud)

查询细分:

update_or_create会尝试与检索对象id=self.id,并version=self.version在数据库中.

  • 找到:对象balanceversion字段将相应地更新Case条件表达式中的值(请参阅答案的下一部分).
  • 未找到:具有id=self.idversion=self.version将要创建的对象,然后它将更新其字段balanceversion字段.

条件查询的细分:

  1. balance 查询:

    • 如果对象存在,则When表达式的条件为true,因此该balance字段将使用以下值更新:

      # Existing balance       # Added amount
         F('balance')      +        amount
      
      Run Code Online (Sandbox Code Playgroud)
    • 如果该对象被创建,它将接收作为初始balanceamount值.

  2. version 查询:

    • 如果对象存在,则When表达式的条件为true,因此该version字段将使用以下值更新:

      # Existing version        # Next Version
         F('version')      +           1
      
      Run Code Online (Sandbox Code Playgroud)
    • 如果对象被创建,它将接收作为初始versionself.version值(它也可以是一个默认的初始版本等1.0.0).


笔记: