代码之家  ›  专栏  ›  技术社区  ›  samfrances

Django条件创建

  •  11
  • samfrances  · 技术社区  · 6 年前

    django orm是否提供了一种有条件地创建对象的方法?

    例如,假设要使用某种乐观并发控制来插入新对象。
    在某一点上,您知道要插入到该表中的最新对象,并且仅当此后未插入新对象时才希望创建新对象。

    如果是更新,则可以根据修订号进行筛选:

    updated = Account.objects.filter(
        id=self.id,
        version=self.version,
    ).update(
        balance=balance + amount,
        version=self.version + 1,
    )
    

    但是,我找不到任何文件化的方法来为 create() save() 打电话。

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

    2 回复  |  直到 6 年前
        1
  •  8
  •   John Moutafis Milani Igor    6 年前

    编辑: 这不是一个 Optimistic Lock 尝试。这是对op提供的代码的直接回答。


    django提供了一种实现 conditional queries . 它还提供 update_or_create(defaults=None, **kwargs) 快捷方式:

    这个 update_or_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
            )
        }
    )
    

    查询的细分:

    这个 更新或创建 将尝试检索对象 id=self.id version=self.version 在数据库中。

    • 发现: 对象的 balance version 字段将使用 Case 相应的条件表达式(见答案的下一节)。
    • 未找到: 对象具有 ID=Self.ID version=self.version版本 将被创建,然后它将获得 平衡 版本 字段已更新。

    条件查询的细分:

    1. 平衡 查询:

      • 如果对象存在,则 When 表达式的条件将为true,因此 平衡 字段将更新为:

        # Existing balance       # Added amount
           F('balance')      +        amount
        
      • 如果对象被创建,它将作为初始值接收 平衡 这个 amount 价值。

    2. 版本 查询:

      • 如果对象存在,则 什么时候? 表达式的条件将为true,因此 版本 字段将更新为:

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


    笔记:

        2
  •  0
  •   Simon Charette    6 年前

    除了 QuerySet.update 返回受影响的行数django不提供任何原语来处理乐观锁。

    不过,也有一些第三方应用提供了这样的功能。

    1. django-concurrency 这是最流行的选项,它同时提供数据库级约束和应用程序级约束
    2. django-optimistic-lock 这是一个有点不受欢迎,但我在过去的项目中尝试过,它工作得很好。
    3. django-locking 未维护。

    编辑:看起来op毕竟不是在追求乐观的锁定解决方案。