本文介绍 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()
链接并使用
来为检索到的对象指定更复杂的条件。例如,检索 Robert 或 Bob Marley(如果存在),否则创建后者:Q objects
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
not
,get_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()
方法的错误行为与
相似。如果需要创建对象并且数据库中已存在 key ,则会引发 create()
。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
字段应该是唯一的。
相关用法
- Python Django QuerySet.get用法及代码示例
- Python Django QuerySet.select_related用法及代码示例
- Python Django QuerySet.union用法及代码示例
- Python Django QuerySet.latest用法及代码示例
- Python Django QuerySet.values用法及代码示例
- Python Django QuerySet.intersection用法及代码示例
- Python Django QuerySet.none用法及代码示例
- Python Django QuerySet.exclude用法及代码示例
- Python Django QuerySet.update_or_create用法及代码示例
- Python Django QuerySet.prefetch_related用法及代码示例
- Python Django QuerySet.first用法及代码示例
- Python Django QuerySet.annotate用法及代码示例
- Python Django QuerySet.dates用法及代码示例
- Python Django QuerySet.values_list用法及代码示例
- Python Django QuerySet.select_for_update用法及代码示例
- Python Django QuerySet.order_by用法及代码示例
- Python Django QuerySet.bulk_update用法及代码示例
- Python Django QuerySet.in_bulk用法及代码示例
- Python Django QuerySet.defer用法及代码示例
- Python Django QuerySet.aggregate用法及代码示例
- Python Django QuerySet.reverse用法及代码示例
- Python Django QuerySet.count用法及代码示例
- Python Django QuerySet.exists用法及代码示例
- Python Django QuerySet.explain用法及代码示例
- Python Django QuerySet.create用法及代码示例
注:本文由纯净天空筛选整理自djangoproject.com大神的英文原创作品 django.db.models.query.QuerySet.get_or_create。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。