创建Django模型或更新(如果存在)


115

我想创建一个模型对象,例如Person,如果不存在person的id,或者我将得到该person对象。

创建新人员的代码如下:

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

但是我不知道在哪里检查并获取现有的人对象。

Answers:


169

如果您正在寻找“如果存在则更新,否则会创建”用例,请参阅@Zags绝佳答案


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

我正在使用django 1.9,它给了我:AttributeError:'QuerySet'对象没有属性'update_or_create'–
Ofek Gila

1
@OfekGila真奇怪,无论是源代码文档确认QuerySetupdate_or_create
bakkal

2
就我而言,代替标识符,我拥有一组字段,它们形成unique_together。这种情况的用法如何?
拉莫

191

目前尚不清楚您的问题是否要求使用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}
)

12
+1,update_or_create因为在这种情况下,总比再次get_or_create调用save()该对象好。
2016年

就我而言,代替标识符,我拥有一组字段,它们形成unique_together。这种情况的用法如何?
拉莫

1
@OmkarDeshpande标识符只是一个例子;您可以传递任何有效的django查询,例如Person.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
Zags

如果要向创建的“人员”添加比默认字段更多的字段怎么办?
罗贝林19'Jul

defaults这些函数的参数@LoBellin 是您在其中指定要添加到模型中的字段的位置。它与模型字段中指定的默认设置无关
Zags


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()命令。


3

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

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

Django提取了使用INSERT或UPDATE SQL语句的需求。具体来说,当您调用save()时,Django遵循以下算法:

如果对象的主键属性设置为计算结果为True的值(即,无或空字符串以外的值),则Django将执行UPDATE。如果未设置对象的主键属性,或者UPDATE未更新任何内容,则Django执行INSERT。

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


1

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

Person.objects.get_or_create(id=1)

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.