当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Python Django QuerySet.get_or_create用法及代码示例


本文介绍 django.db.models.query.QuerySet.get_or_create 的用法。

声明

get_or_create(defaults=None, **kwargs)

一种使用给定 kwargs 查找对象的便捷方法(如果您的模型具有所有字段的默认值,则可能为空),如有必要,创建一个。

返回 (object, created) 的元组,其中 object 是检索或创建的对象, created 是指定是否创建新对象的布尔值。

这是为了防止在并行发出请求时创建重复的对象,并作为样板代码的快捷方式。例如:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

在这里,对于并发请求,可能会多次尝试保存具有相同参数的Person。为了避免这种竞争条件,可以使用get_or_create() 重写上面的示例,如下所示:

obj, created = Person.objects.get_or_create(
    first_name='John',
    last_name='Lennon',
    defaults={'birthday': date(1940, 10, 9)},
)

任何传递给 get_or_create() 的关键字参数——except 一个可选的 defaults——都将在 get() 调用中使用。如果找到一个对象,get_or_create() 返回该对象和 False 的元组。

警告

假设数据库强制关键字参数的唯一性(请参阅 unique unique_together ),此方法是原子的。如果关键字参数中使用的字段没有唯一性约束,则对该方法的并发调用可能会导致插入具有相同参数的多行。

您可以通过将 get_or_create()filter() 链接并使用 Q objects 来为检索到的对象指定更复杂的条件。例如,检索 Robert 或 Bob Marley(如果存在),否则创建后者:

from django.db.models import Q

obj, created = Person.objects.filter(
    Q(first_name='Bob') | Q(first_name='Robert'),
).get_or_create(last_name='Marley', defaults={'first_name': 'Bob'})

如果找到多个对象,则 get_or_create() 引发 MultipleObjectsReturned 。如果找到一个对象 notget_or_create() 将实例化并保存一个新对象,返回一个新对象和 True 的元组。新对象将大致按照以下算法创建:

params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()

在英语中,这意味着以任何不包含双下划线的非 'defaults' 关键字参数开头(这将指示不精确的查找)。然后添加 defaults 的内容,必要时覆盖任何键,并将结果用作模型类的关键字参数。如果 defaults 中有任何可调用对象,请评估它们。正如上面所暗示的,这是所使用算法的简化,但它包含所有相关的细节。内部实现有比这更多的error-checking,并处理一些额外的edge-conditions;如果您有兴趣,请阅读代码。

如果您有一个名为 defaults 的字段并希望将其用作 get_or_create() 中的精确查找,请使用 'defaults__exact' ,如下所示:

Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})

当您使用手动指定的主键时,get_or_create() 方法的错误行为与 create() 相似。如果需要创建对象并且数据库中已存在 key ,则会引发 IntegrityError

最后,关于使用的一句话get_or_create()在 Django 视图中。请确保仅在POST请求,除非您有充分的理由不这样做。GET请求不应该对数据产生任何影响。相反,使用POST每当对页面的请求对您的数据产生副作用时。有关更多信息,请参阅安全方法在 HTTP 规范中。

警告

您可以使用get_or_create() ManyToManyField 属性和反向关系。在这种情况下,您将在该关系的上下文中限制查询。如果您不始终如一地使用它,这可能会导致您出现一些完整性问题。

为以下型号:

class Chapter(models.Model):
    title = models.CharField(max_length=255, unique=True)

class Book(models.Model):
    title = models.CharField(max_length=256)
    chapters = models.ManyToManyField(Chapter)

您可以通过 Book 的 chapters 字段使用get_or_create(),但它只在该书的上下文中获取:

>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError

发生这种情况是因为它试图通过书 “Ulysses” 获取或创建“第 1 章”,但它无法执行任何操作:关系无法获取该章,因为它与该书无关,但是它也无法创建它,因为title 字段应该是唯一的。

相关用法


注:本文由纯净天空筛选整理自djangoproject.com大神的英文原创作品 django.db.models.query.QuerySet.get_or_create。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。