Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.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条件创建_Python_Django_Django Orm - Fatal编程技术网

Python Django条件创建

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

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

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

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

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
      的对象,然后将更新其
      余额
      版本
      字段

    条件查询的细分:

  • 余额
    查询:

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

      # Existing balance       # Added amount
         F('balance')      +        amount
      
      # Existing version        # Next Version
         F('version')      +           1
      
    • 如果对象被创建,它将作为初始
      余额
      接收
      金额

  • 版本
    查询:

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

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


  • 注:

    • 您可能需要为
      大小写
      表达式提供一个
      output_字段
      参数,请查看
    • 出于对
      F()
      表达式是什么以及它是如何使用的好奇(双关语),我这里有一个问答风格的示例:

    您之前要测试的条件是什么?看看这个,它可以是任何东西。“如果少于100个,则创建一个新的X”。表级锁可能有意义的任何东西(如果您希望使用锁而不是乐观的方法)。好的!所以我上面评论中的链接会起作用,我不知道我是怎么理解的。第一个版本似乎创建了一个实例(如果实例还不存在的话),这是一组更受限制的条件。第二个创建或更新(我只想创建)。两者似乎都容易受到竞争条件的影响,因为它们进行两次查询,一次是检查某个条件是否得到,然后(假设在此期间没有任何变化)创建一个对象。我希望django ORM能够帮助用户在一个查询中完成这个操作。但是我的理解很可能有缺陷。@samfrances:但是如果你在
    修订版
    编号上加上一个
    唯一的
    ,那么如果有人已经构建了这样的修订版,那么创建就会失败。这难道不能解决问题吗?例如,如果您有
    iban,rev,value
    ,您可以将
    unique\u约束在一起=(('iban','rev'),)
    ,那么数据库将强制不存在具有相同
    iban
    rev
    的两行。因此,
    .create(…)
    将失败,因此您可以针对这些约束设置条件。如果您需要更复杂的约束,通常可以在数据库中对这些约束进行编码(例如
    检查值>0
    。我认为在这里使用
    更新或创建
    并不合适。乐观锁定的目的是避免覆盖现有条目(例如,在版本不匹配时)不在不匹配时创建新的。@SimonCharette这不是乐观锁定的尝试。这是一个直接的答案,使用实际的OP代码(我可能应该将其编辑到答案中…).你是对的,我错读了OP的问题,因此删除了我的否决票。我以为OP在寻找乐观的锁定解决方案。@SimonCharette没问题。我编辑了我的答案,以反映它直接回答了提供的代码!