【问题标题】:Create Django model or update if exists创建 Django 模型或更新(如果存在)
【发布时间】:2012-12-16 10:08:50
【问题描述】:

我想创建一个模型对象,比如 Person,如果人的 id 不存在,或者我会得到那个人对象。

新建人物的代码如下:

class Person(models.Model):
    identifier = models.CharField(max_length = 10)
    name = models.CharField(max_length = 20)
    objects = PersonManager()

class PersonManager(models.Manager):
    def create_person(self, identifier):
        person = self.create(identifier = identifier)
        return person

但我不知道在哪里检查和获取现有的 person 对象。

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    目前尚不清楚您的问题是询问get_or_create 方法(至少可从Django 1.3 获得)还是update_or_create 方法(Django 1.7 中的新方法)。这取决于您要如何更新用户对象。

    使用示例如下:

    # In both cases, the call will get a person object with matching
    # identifier or create one if none exists; if a person is created,
    # it will be created with name equal to the value in `name`.
    
    # In this case, if the Person already exists, its existing name is preserved
    person, created = Person.objects.get_or_create(
            identifier=identifier, defaults={"name": name}
    )
    
    # In this case, if the Person already exists, its name is updated
    person, created = Person.objects.update_or_create(
            identifier=identifier, defaults={"name": name}
    )
    

    【讨论】:

    • +1 for update_or_create 因为对于那个用例,它比 get_or_create 更好,只是在对象上再次调用 save()
    • 在我的例子中,代替标识符,我有一组字段,它们形成了 unique_together。本案使用情况如何?
    • @OmkarDeshpande 标识符只是一个例子;您可以传入任何有效的 django 查询,例如 Person.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
    • 如果我想向创建的 Person 添加比默认字段更多的字段怎么办?
    • @LoBellin defaults 这些函数的参数是您指定要添加到模型中的字段的位置。它与模型字段上指定的默认值无关
    【解决方案2】:

    如果您正在寻找“如果存在则更新”用例,请参考@Zags excellent answer


    Django 已经有一个get_or_createhttps://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

    对你来说可能是:

    id = 'some identifier'
    person, created = Person.objects.get_or_create(identifier=id)
    
    if created:
       # means you have created a new person
    else:
       # person just refers to the existing one
    

    【讨论】:

      【解决方案3】:

      Django 对此有支持,请查看get_or_create

      person, created = Person.objects.get_or_create(name='abc')
      if created:
          # A new person object created
      else:
          # person object already exists
      

      【讨论】:

        【解决方案4】:

        update_or_create 仅适用于少量对象,但如果您要处理大型集合,则无法很好地扩展。 update_or_create 总是先运行 SELECT,然后再运行 UPDATE。

        for the_bar in bars:
            updated_rows = SomeModel.objects.filter(bar=the_bar).update(foo=100)
                if not updated_rows:
                    # if not exists, create new
                    SomeModel.objects.create(bar=the_bar, foo=100)
        

        这充其量只会运行第一个更新查询,并且只有当它匹配零行时才会运行另一个 INSERT 查询。如果您希望大多数行实际存在,这将大大提高您的性能。

        不过,这一切都取决于您的用例。如果您期望主要是插入,那么bulk_create() 命令可能是一个选项。

        【讨论】:

          【解决方案5】:

          我想我会添加一个答案,因为您的问题标题看起来像是在询问如何创建或更新,而不是按照问题正文中的描述获取或创建。

          如果您确实想要创建或更新一个对象,默认情况下 .save() 方法已经具有此行为,来自the docs

          Django 抽象出使用 INSERT 或 UPDATE SQL 语句的需要。 具体来说,当你调用 save() 时,Django 遵循这个算法:

          如果对象的主键属性设置为计算值 为 True(即,除 None 或空字符串以外的值),Django 执行更新。如果对象的主键属性没有设置 或者如果 UPDATE 没有更新任何东西,Django 会执行 INSERT。

          值得注意的是,当他们说“如果 UPDATE 没有更新任何内容”时,他们实质上是指您提供给对象的 id 不存在于数据库中的情况。

          【讨论】:

            【解决方案6】:

            您也可以像 get_or_create 一样使用 update_or_create,下面是我为 update_or_create 遵循的模式,假设模型 Person 具有 id(键)、名称、年龄、is_manager 作为属性 -

            update_values = {"is_manager": False}
            new_values = {"name": "Bob", "age": 25, "is_manager":True}
            
            obj, created = Person.objects.update_or_create(identifier='id',
                                                           defaults=update_values)
            if created:
                obj.update(**new_values)
            

            【讨论】:

              【解决方案7】:

              如果您创建时的输入之一是主键,这就足够了:

              Person.objects.get_or_create(id=1)
              

              如果存在两个具有相同主键的数据是不允许的,它将自动更新。

              【讨论】:

                【解决方案8】:

                这应该是您正在寻找的答案

                EmployeeInfo.objects.update_or_create(
                    #id or any primary key:value to search for
                    identifier=your_id, 
                    #if found update with the following or save/create if not found
                    defaults={'name':'your_name'}
                )
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-10-18
                  • 1970-01-01
                  • 2017-05-01
                  • 1970-01-01
                  • 2017-12-28
                  • 2015-06-13
                  • 1970-01-01
                  相关资源
                  最近更新 更多