QuerySetAPI参考¶
本文档描述QuerySetAPI它建立在模型和数据库查询指南,所以在阅读本文档之前,您可能需要阅读和理解这些文档。
在整个引用中,我们将使用示例Weblog模型在数据库查询指南.
什么时候QuerySetS值¶
在内部,aQuerySet可以构造、过滤、切片,并且通常可以在不实际访问数据库的情况下传递。在对查询集进行评估之前,实际上不会发生任何数据库活动。
您可以评估QuerySet以下列方式:
迭代 A QuerySet是可迭代的,并且它在您第一次遍历数据库查询时执行它的数据库查询。例如,这将打印数据库中所有条目的标题:
for e in Entry.objects.all():
print(e.headline)
注意:如果您只想确定至少存在一个结果,就不要使用它。它的使用效率更高exists().
切片。
如在限制查询集…QuerySet可以使用Python的数组切片语法进行切片。切割未评估的QuerySet通常返回另一个未评估的QuerySet,但是Django将执行数据库查询,如果您使用片语法的“STEP”参数,并返回一个列表。切片QuerySet也返回一个列表。
还请注意,即使切分一个未评估的QuerySet返回另一个未评估的QuerySet不允许进一步修改它(例如,添加更多过滤器或修改排序),因为这不能很好地转换为SQL,而且它也没有明确的含义。
QuerySet当您调用repr()
在上面。这是为了方便Python交互式解释器,所以您可以在交互使用API时立即看到结果。
QuerySet当您调用len()
在上面。如您所料,这将返回结果列表的长度。
注意:如果您只需要确定集合中的记录数(而不需要实际的对象),那么使用SQL的SELECT COUNT(*)…Django提供了一个count()方法正是出于这个原因。
entry_list = list(Entry.objects.all())
Bool()测试aQuerySet在布尔上下文中,例如使用bool(), or, 和或者if语句,将导致执行查询。如果至少有一个结果,则QuerySet是True,否则False…例如:
if Entry.objects.filter(headline="Test"):
print("There is at least one Entry with the headline Test")
注意:如果您只想确定是否至少存在一个结果(而不需要实际对象),则使用它更有效exists().
QuerySets¶
如果你pickle a QuerySet,这将强制将所有结果加载到内存中,然后再进行酸洗。pickle 通常被用作缓存的先驱,当缓存的查询集被重新加载时,您希望结果已经出现并准备好使用(从数据库读取可能需要一些时间,从而使缓存的目的落空)。这意味着当你打开一个QuerySet,它包含的结果在它被腌制的时候,而不是目前在数据库中的结果。
如果您只想挑选必要的信息以重新创建QuerySet之后,从数据库中提取query属性的QuerySet…然后,您可以重新创建原始QuerySet(没有加载任何结果)使用如下代码:
>>> import pickle
>>> query = pickle.loads(s) # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query # Restore the original 'query'.
这个query属性是一个不透明的对象。它表示查询构造的内部,而不是公共API的一部分。但是,像这里所描述的那样,对属性的内容进行分类和解压缩是安全的(并且得到了充分的支持)。
您不能在不同版本之间共享泡菜
泡菜QuerySets只对用于生成它们的Django版本有效。如果您使用Django版本N生成泡菜,则不能保证用Django版本N+1可以读取泡菜。Pickles不应该作为长期存档策略的一部分。
由于泡菜兼容性错误很难诊断,例如悄悄损坏的对象,RuntimeWarning当您尝试在Django版本中解压缩与被腌制的查询集不同的查询集时引发。
QuerySetAPI¶
这是一个正式的声明QuerySet:
班级QuerySet(模型=无, 查询=无, 使用=无)[源代码]¶
通常情况下,您将与QuerySet你会用它链式过滤器…为了让这件事成功,大多数人QuerySet方法返回新的查询集。本节后面将详细介绍这些方法。
这个QuerySet类有两个可用于内省的公共属性:
ordered¶
True如果QuerySet是有序的,即有一个order_by()
子句或模型上的默认排序。False不然的话。
db¶
如果现在执行此查询,将使用的数据库。
注解
这个query参数QuerySet存在,以便专用查询子类可以重构内部查询状态。参数的值是该查询状态的不透明表示,不是公共API的一部分。简单地说:如果你需要问,你不需要使用它。
返回新方法的QuerySets¶
Django提供了一系列QuerySet对象返回的结果类型进行修改的精化方法。QuerySet或其SQL查询的执行方式。
filter()¶
function filter() { [native code] }(**)¶
返回一个新的QuerySet包含匹配给定查找参数的对象。
查找参数(**)应采用字段查找下面。多个参数通过AND在基础SQL语句中。
如果需要执行更复杂的查询(例如,使用OR语句),您可以使用Q objects.
exclude()¶
exclude(**)¶
返回一个新的QuerySet包含执行以下操作的对象不匹配给定的查找参数。
查找参数(**)应采用字段查找下面。多个参数通过AND在底层sql语句中,并且整个事件都包含在NOT().
此示例不包括其pub_date晚于2005-1-3,且其headline是“你好”:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
在SQL术语中,计算结果为:
SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
此示例不包括其pub_date晚于2005-1-3年或其标题为“Hello”的:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
在SQL术语中,计算结果为:
SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'
注意,第二个示例的限制性更强。
如果需要执行更复杂的查询(例如,使用OR语句),您可以使用Q objects.
annotate()¶
annotate(*ARGS, **)¶
类中的每个对象进行注释。
QuerySet提供的清单查询表达式…表达式可以是一个简单的值,一个对模型上的字段(或任何相关模型)的引用,也可以是一个聚合表达式(平均值、和等)。类中与对象相关的对象上计算的QuerySet.
每一个论点annotate()是将添加到QuerySet还回来了。
Django提供的聚合函数在聚合函数下面。
使用关键字参数指定的注释将使用关键字作为注释的别名。匿名参数将根据聚合函数的名称和正在聚合的模型字段为它们生成一个别名。只有引用单个字段的聚合表达式才能是匿名参数。其他一切都必须是关键字参数。
例如,如果您正在操作一个博客列表,您可能需要确定每个博客中有多少条目:
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42
这个Blog模型没有定义entry__count属性本身,但通过使用关键字参数指定聚合函数,您可以控制注释的名称:
>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
order_by()¶
order_by(*字段)¶
默认情况下,由QuerySet的排序元组。ordering模型中的选项元…你可以在-QuerySet使用order_by方法。
例子:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
以上结果将由pub_date下降,然后headline上升。前面的负号"-pub_date"指示降秩序。升序是隐含的。若要随机订购,请使用"?",就像这样:
Entry.objects.order_by('?')
注:order_by(’?’)查询可能是昂贵和缓慢的,这取决于您正在使用的数据库后端。
若要按不同模型中的字段进行排序,请使用与查询不同模型关系时相同的语法。也就是说,字段的名称,后面跟着一个双下划线(__),然后是新模型中字段的名称,等等,用于您想要加入的任意多个模型。例如:
Entry.objects.order_by('blog__name', 'headline')
如果您试图按与另一个模型相关的字段进行排序,Django将在相关模型上使用默认排序,如果没有相关模型的主键,则使用OrderMeta.ordering指定。例如,由于Blog模型没有指定默认排序:
Entry.objects.order_by('blog')
.是完全相同的:
Entry.objects.order_by('blog__id')
如果Blog有ordering = [‘name’],则第一个查询集将与以下内容相同:
Entry.objects.order_by('blog__name')
您也可以按查询表达式打电话asc()或desc()关于这句话:
Entry.objects.order_by(Coalesce('summary', 'headline').desc())
在相关模型中按字段排序时要小心,如果您也在使用distinct()…见distinct()有关相关模型排序如何更改预期结果的说明。
注解
允许指定一个多值字段来对结果排序(例如,ManyToManyField字段,或ForeignKey)。
考虑这一情况:
class Event(Model):
parent = models.ForeignKey(
'self',
on_delete=models.CASCADE,
related_name='children',
)
date = models.DateField()
Event.objects.order_by('children__date')
在这里,每个数据可能存在多个排序数据。Event;每个Event多倍children将多次返回到新的QuerySet那order_by()创造。换句话说,使用order_by()在QuerySet可以返回更多的项目,比您开始的工作-这可能是既没有预期,也没有用处。
因此,在使用多值字段对结果排序时要小心。如果您可以确保您要订购的每个项目只有一个排序数据,这种方法不应该出现问题。如果没有,确保结果是你所期望的。
无法指定排序是否应区分大小写。关于区分大小写的问题,Django将命令结果,但是数据库后端通常会对结果进行排序。
您可以按转换为小写的字段进行排序。
Lower这将实现案例一致的排序:
Entry.objects.order_by(Lower('headline').desc())
如果不希望将任何排序应用于查询,即使是默认的排序,请调用order_by()没有参数。
您可以通过检查QuerySet.ordered属性,它将是True如果QuerySet已经被以任何方式下令。
各order_by()呼叫将清除任何先前的订单。例如,此查询将由pub_date而不是headline:
Entry.objects.order_by('headline').order_by('pub_date')
警告
订购不是免费的操作。添加到订单中的每个字段都会给数据库带来成本。您添加的每个外键也将隐式地包含其所有默认命令。
如果查询没有指定顺序,则将以未指定的顺序从数据库返回结果。只有当一组字段唯一地标识结果中的每个对象时,才能保证特定的排序。例如,如果name字段不是唯一的,按其排序不能保证名称相同的对象总是以相同的顺序出现。
reverse()¶
function reverse() { [native code] }()¶
使用reverse()方法来反转返回queryset元素的顺序。呼叫reverse()第二次将排序恢复到法线方向。
要检索查询集中的“最后”五个项,可以这样做:
my_queryset.reverse()[:5]
请注意,这与在Python中从序列末尾切片是不完全一样的。上面的示例将首先返回最后一项,然后返回倒数第二项,以此类推。如果我们有一个Python序列seq[-5:]我们会先看第五条-最后一条。Django不支持这种访问模式(从末尾切片),因为在SQL中不可能高效地这样做。
另外,请注意reverse()应该只在QuerySet它具有定义的排序(例如,当对定义默认排序的模型进行查询时,或者在使用order_by())。如果没有为给定的QuerySet,呼叫reverse()对此没有实际影响(在调用之前,顺序是未定义的。)reverse(),之后仍将不确定)。
distinct()¶
distinct(*字段)¶
返回一个新的QuerySet用SELECT DISTINCT在其SQL查询中。这将消除查询结果中重复的行。
默认情况下,QuerySet不会消除重复行
。在实践中,这很少是一个问题,因为简单的查询,如Blog.objects.all()不要引入重复结果行的可能性。但是,如果查询跨多个表,则可以在QuerySet被评估。那时你就会用distinct().
注解
中使用的任何字段。order_by()调用包含在sql中。SELECT柱子。当结合使用时,有时会导致意外的结果。distinct()…如果您从相关模型中按字段排序,这些字段将被添加到选定的列中,它们可能会使其他重复的行看起来是不同的。由于额外的列不会出现在返回的结果中(它们只是为了支持排序),所以有时看起来返回的结果不完全相同。
类似地,如果使用values()查询以限制所选列,order_by()(或默认的模型排序)仍将涉及,并可能影响结果的唯一性。
这里的寓意是如果你用distinct()小心相关模型的订购。类似地,当使用distinct()和values()在一起时,在按字段排序时要小心,而不是在values()打电话。
仅在PostgreSQL上,可以传递位置参数(*字段),以便指定DISTINCT应该适用。这转化为SELECT DISTINCT ONSQL查询这就是区别。对于正常人distinct()调用,数据库比较各在确定哪些行是不同的时,每一行中的字段。为了distinct()使用指定字段名调用时,数据库将只比较指定的字段名。
注解
指定字段名时,必提供order_by()在QuerySet,以及田里的土地order_by()必须从distinct(),按相同的顺序排列。
例如,SELECT DISTINCT ON (a)为列中的每个值提供第一行。a…如果您不指定一个订单,您将得到一些任意行。
示例(第一个之后的示例只适用于PostgreSQL):
>>> Author.objects.distinct()
[...]
>>> Entry.objects.order_by('pub_date').distinct('pub_date')
[...]
>>> Entry.objects.order_by('blog').distinct('blog')
[...]
>>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
[...]
>>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
[...]
>>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]
注解
记住order_by()使用任何已定义的默认相关模型排序。您可能必须根据关系显式地排序。_id或引用字段以确保DISTINCT ON表达式匹配ORDER BY条款。例如,如果Blog模型定义了ordering通过name:
Entry.objects.order_by('blog').distinct('blog')
.无法工作,因为查询将由blog__name因此,不匹配DISTINCT ON表情。你必须明确地按关系排序_id字段(blog_id在本例中)或引用的(blog__pk)以确保两个表达式匹配。
values()¶
function values() { [native code] }(*字段, **表达)¶
返回QuerySet当用作可迭代时,返回字典而不是模型实例。
这些字典中的每一个都表示一个对象,其键对应于模型对象的属性名称。
本示例比较values()对于普通模型对象:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
这个values()方法采用可选的位置参数,*字段,指定SELECT应该是有限的。如果指定字段,则每个字典只包含指定字段的字段键/值。如果不指定字段,则每个字典都将包含数据库表中每个字段的键和值。
例子:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
这个values()方法还接受可选的关键字参数,**表达,被传递到annotate():
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>
您可以使用内置和自定义查找下订单。例如:
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values('name__lower')
<QuerySet [{'name__lower': 'beatles blog'}]>
更改为Django 2.1:
增加了对查找的支持。
在values()子句在同一个参数中的其他参数之前应用。values()条款。如果需要按另一个值进行分组,请将其添加到前面的values()代之以子句。例如:
>>> from django.db.models import Count
>>> Blog.objects.values('entry__authors', entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values('entry__authors').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
值得一提的几个微妙之处:
如果您有一个名为foo那是一个ForeignKey,默认values()调用将返回一个名为foo_id,因为这是存储实际值的隐藏模型属性的名称(foo属性是指相关模型)。当你打电话的时候values()传入字段名,您可以传入foo或foo_id您将得到相同的东西(字典键将匹配您传入的字段名)。
例如:
>>> Entry.objects.values()
<QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
>>> Entry.objects.values('blog')
<QuerySet [{'blog': 1}, ...]>
>>> Entry.objects.values('blog_id')
<QuerySet [{'blog_id': 1}, ...]>
使用时values()连同distinct(),注意排序会影响结果。
如果您使用values()从句extra()调用,任何由select在extra()必须显式地包含在values()打电话。任何extra()打完电话values()调用将被忽略其额外的选定字段。
呼叫only()和defer()后values()没有意义,所以这样做会引发NotImplementedError.
组合转换和聚合需要使用两个annotate()调用,显式调用或作为关键字参数调用values()…如前所述,如果转换已在相关字段类型上注册,则为第一个annotate()可以省略,因此以下示例是等价的:
>>> from django.db.models import CharField, Count
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>
>>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
>>> Blog.objects.values(
... entry__authors__name__lower=Lower('entry__authors__name')
... ).annotate(entries=Count('entry'))
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
>>> Blog.objects.annotate(
... entry__authors__name__lower=Lower('entry__authors__name')
... ).values('entry__authors__name__lower').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
当您知道只需要来自少数可用字段的值,并且不需要模型实例对象的功能时,它非常有用。只选择需要使用的字段更有效。
最后,请注意,您可以调用filter(), order_by()等values()这意味着这两个呼叫是相同的:
Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()
创建Django的人更喜欢将所有SQL影响的方法放在第一位,然后(可选)是任何影响输出的方法(例如values()),但这并不重要。这是你真正炫耀你的个人主义的机会。
您还可以通过以下方法引用具有反向关系的相关模型上的字段OneToOneField, ForeignKey和ManyToManyField属性:
>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
警告
因为ManyToManyField属性和反向关系可以有多个相关行,包括这些行会对结果集的大小产生乘数效应。如果在您的values()查询,在这种情况下,将返回所有可能的组合。
values_list()¶
values_list(*字段, 平=假, 命名=假)¶
这类似于values()除了返回字典之外,它在迭代时返回元组。
每个元组包含传递给values_list()调用-所以第一个项是第一个字段,等等。例如:
>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list('id', Lower('headline'))
<QuerySet [(1, 'first entry'), ...]>
如果您只传入一个字段,也可以传入function flat() { [native code] }参数。如果True,这意味着返回的结果是单个值,而不是一个元组。
一个例子应该使区别变得更清楚:
>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>
这是一个错误的传递function flat() { [native code] }当有不止一个字段的时候。
你可以通过named=True作为一个namedtuple():
>>> Entry.objects.values_list('id', 'headline', named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
使用命名元组可能会使用更易读的结果,而牺牲了将结果转换为命名元组的小性能损失。
如果你不把任何值传递给values_list(),它将按声明的顺序返回模型中的所有字段。
一个常见的需求是获取某个模型实例的特定字段值。要实现这一点,请使用values_list()后面是get()呼叫:
>>> Entry.objects.values_list('headline', flat=True).get(pk=1)
'First entry'
values()和values_list()都是作为特定用例的优化:检索数据的子集,而不需要创建模型实例的开销。
这个比喻在处理多到多和其他多值关系(例如反向外键的一对多关系)时分崩离析,因为“一行一物”假设不成立。
例如,在查询ManyToManyField:
>>> Author.objects.values_list('name', 'entry__headline')
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
具有多个条目的作者多次出现,没有任何条目的作者有None为了条目标题。
类似地,当查询反向外键时,None出现在没有任何作者的条目中:
>>> Entry.objects.values_list('authors')
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
在Django 2.0中更改:
这个named参数添加。
dates()¶
dates(场域, 仁爱, Order=‘ASC’)¶
返回QuerySet的计算结果为datetime.date对象中表示特定类型的所有可用日期的QuerySet.
场域应该是DateField你的模特。仁爱应该是"year", “month”, “week”,或"day"…各datetime.date对象的结果列表中的对象被“截断”到给定的type.
"year"返回字段所有不同年份值的列表。
"month"返回字段所有不同年份/月值的列表。
"week"返回字段所有不同年份/周值的列表。所有日期都是星期一。
"day"返回字段的所有不同年份/月/日值的列表。
order,默认为’ASC’,应该是’ASC’或’DESC’…这指定了如何排序结果。
例子:
>>> Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'week')
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]
更改为Django 2.1:
增加了“一周”支助。
datetimes()¶
datetimes(字段名, 仁爱, Order=‘ASC’, tzinfo=无)¶
返回QuerySet的计算结果为datetime.datetime对象中表示特定类型的所有可用日期的QuerySet.
字段名应该是DateTimeField你的模特。
应该是"year", "month", "week", "day", "hour", "minute",或"second"...
各datetime.datetime对象的结果列表中的对象被“截断”到给定的type.
order,默认为’ASC’,应该是’ASC’或’DESC’…这指定了如何排序结果。
tzinfo定义在截断之前转换日期时间的时区。事实上,给定的日期时间根据使用中的时区有不同的表示形式。此参数必须是datetime.tzinfo对象。如果是None,Django使用当前时区…当USE_TZ是False.
更改为Django 2.1:
增加了“一周”支助。
注解
此函数直接在数据库中执行时区转换。因此,数据库必须能够解释tzinfo.tzname(None)...
这转化为以下要求:
SQLite:没有要求。转换在Python中执行比兹(安装Django时安装)。
PostgreSQL:没有要求(请参阅时区).
Oracle:没有要求(见选择时区文件).
MySQL:用MySQL_tzinfo_to_sql.
none()¶
none()¶
调用NONE()将创建一个永远不返回任何对象的查询集,并且在访问结果时不会执行任何查询。
一个qs.no()queryset是EmptyQuerySet.
例子:
>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
all()¶
all()¶
返回复制流QuerySet(或QuerySet(子类)。在您可能希望传递模型管理器或QuerySet并对结果进行进一步的过滤。打电话后all()在任何一个对象上,你肯定会有一个QuerySet一起工作。
当QuerySet是评价,它通常缓存其结果。如果数据库中的数据可能在QuerySet,则可以通过以下方式获得相同查询的更新结果:all()在先前评估过的QuerySet.
union()¶
union(*其他质量标准, ALL=假)¶
使用SQL的UNION运算符将两个或多个结果组合在一起。
QuerySet例如:
>>> qs1.union(qs2, qs3)
这个UNION运算符默认情况下只选择不同的值。若要允许重复值,请使用all=True争论。
union(), intersection(),和difference()类型的返回模型实例QuerySet即使争论是QuerySet其他型号的。
传递不同的模型,只要SELECT列表在所有方面都是相同的。QuerySets(至少类型、名称与类型的顺序相同并不重要)。在这种情况下,必须使用第一个QuerySet在……里面QuerySet方法应用于生成的QuerySet…例如:
>>> qs1 = Author.objects.values_list('name')
>>> qs2 = Entry.objects.values_list('headline')
>>> qs1.union(qs2).order_by('name')
此外,只有LIMIT, OFFSET, COUNT(*), ORDER BY,并指定列(即切片,count(), order_by(),和values()/values_list())允许对生成的QuerySet…此外,数据库对组合查询中允许的操作设置了限制。例如,大多数数据库不允许LIMIT或OFFSET在合并查询中。
intersection()¶
intersection(*其他质量标准)¶
使用SQL的INTERSECT运算符返回两个或多个共享元素。
QuerySet例如:
>>> qs1.intersection(qs2, qs3)
看见union()一些限制。
difference()¶
difference(*其他质量标准)¶
使用SQL的EXCEPT运算符仅保留在QuerySet但不是在别的地方QuerySet例如:
>>> qs1.difference(qs2, qs3)
看见union()一些限制。
select_related()¶
select_related(*字段)¶
返回QuerySet这将“跟随”外键关系,在执行其查询时选择其他相关对象数据。这是一个性能提升器,它会导致一个更复杂的查询,但这意味着以后使用外键关系将不需要数据库查询。
下面的示例说明了普通查找和select_related()查一下。下面是标准查找:
# Hits the database.
e = Entry.objects.get(id=5)
# Hits the database again to get the related Blog object.
b = e.blog
下面是select_related查找:
# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)
# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
你可以用select_related()使用任何查询集的对象:
from django.utils import timezone
# Find all the blogs with entries scheduled to be published in the future.
blogs = set()
for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog'):
# Without select_related(), this would make a database query for each
# loop iteration in order to fetch the related blog for each entry.
blogs.add(e.blog)
按…的顺序filter()和select_related()锁链并不重要。这些查询集是等价的:
Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
您可以使用与查询外键类似的方式跟踪外键。如果您有以下模型:
from django.db import models
class City(models.Model):
# ...
pass
class Person(models.Model):
# ...
hometown = models.ForeignKey(
City,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
class Book(models.Model):
# ...
author = models.ForeignKey(Person, on_delete=models.CASCADE)
…然后Book.objects.select_related('author__hometown').get(id=4)
将缓存相关的Person
和相关City
:
# Hits the database with joins to the author and hometown tables.
b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author # Doesn't hit the database.
c = p.hometown # Doesn't hit the database.
# Without select_related()...
b = Book.objects.get(id=4) # Hits the database.
p = b.author # Hits the database.
c = p.hometown # Hits the database.
你可以参考任何ForeignKey或OneToOneField传递给的字段列表中的关系。select_related().
还可以引用OneToOneField在传递给select_related-也就是说,你可以通过OneToOneField返回到定义字段的对象。而不是指定字段名,而是使用related_name用于相关对象上的字段。
在某些情况下,你可能想打电话给select_related()有很多相关的对象,或者你不知道所有的关系。在这种情况下,可以调用select_related()没有争论。
这将跟随它可以找到的所有非空外键,必须指定-nullable外键。在大多数情况下不建议这样做,因为它可能会使底层查询变得更加复杂,并且返回比实际需要的更多的数据。
如果您需要清除过去调用的select_related在.上QuerySet,
你可以通过None作为参数:
>>> without_relations = queryset.select_related(None)
链子select_related调用的工作方式类似于其他方法--也就是说select_related('foo', 'bar')等于select_related('foo').select_related('bar').
prefetch_related()¶
prefetch_related(*查阅)¶
返回QuerySet它将在单个批处理中自动检索每个指定查找的相关对象
。
这有一个类似的目的select_related,这两种方法都是为了阻止访问相关对象所造成的数据库查询泛滥,但是策略是不同的
。
select_related通过创建SQL联接并将相关对象的字段包含在SELECT声明。因此,select_related获取同一数据库查询中的相关对象。然而,为了避免加入“许多”关系而产生的大得多的结果集,select_related仅限于单值关系外键和一对一的关系。
prefetch_related另一方面,分别查找每个关系,并在Python中进行“连接”。这允许它预取多对多和多对一的对象,这些对象不能使用select_related支持的外键和一对一关系。select_related…它还支持预取GenericRelation和GenericForeignKey然而,它必须被限制在一组一致的结果上。例如,预取由GenericForeignKey只有当查询被限制为一个时,才支持ContentType.
例如,假设您有以下模型:
from django.db import models
class Topping(models.Model):
name = models.CharField(max_length=30)
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
def __str__(self):
return "%s (%s)" % (
self.name,
", ".join(topping.name for topping in self.toppings.all()),
)
然后跑:
>>> Pizza.objects.all()
["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...
问题是每次Pizza.str()索要self.toppings.all()它必须查询数据库,所以Pizza.objects.all()将在toppings表上运行查询每个比萨中的物品QuerySet.
我们可以使用prefetch_related:
>>> Pizza.objects.all().prefetch_related('toppings')
这意味着self.toppings.all()每人Pizza现在每一次self.toppings.all()调用,而不必转到数据库中获取项,它将在预取中找到它们。QuerySet在单个查询中填充的缓存。
也就是说,所有相关的说明都将在一个查询中获取,并用于QuerySets具有相关结果的预填充缓存;QuerySets然后在self.toppings.all()
。
中的附加查询prefetch_related()之后执行。QuerySet已开始计算,主查询已执行。
如果您有模型实例的可迭代性,则可以使用prefetch_related_objects()功能。
注意,主服务器的结果缓存QuerySet然后,所有指定的相关对象将全部加载到内存中。这改变了QuerySets,它通常试图避免在需要所有对象之前将它们加载到内存中,即使在数据库中执行了查询之后也是如此。
注解
记住,和往常一样QuerySets,任何包含不同数据库查询的后续链接方法都将忽略以前缓存的结果,并使用新的数据库查询检索数据。因此,如果您编写以下内容:
>>> pizzas = Pizza.objects.prefetch_related('toppings')
>>> [list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]
.那么事实是pizza.toppings.all()已经被抢了也帮不了你。这个prefetch_related(‘toppings’)默示pizza.toppings.all(),但是pizza.toppings.filter()是一个新的不同的查询。预取缓存在这里起不了作用;
实际上,它损害了性能,因为您已经完成了没有使用过的数据库查询。因此,请谨慎使用此功能!
此外,如果您调用数据库更改方法add(), remove(), clear()或set()
上related managers,将清除该关系的任何预取缓存。
还可以使用普通联接语法来处理相关字段的相关字段。假设我们在上面的例子中有一个额外的模型:
class Restaurant(models.Model):
pizzas = models.ManyToManyField(Pizza, related_name='restaurants')
best_pizza = models.ForeignKey(Pizza, related_name='championed_by', on_delete=models.CASCADE)
以下都是合法的:
>>> Restaurant.objects.prefetch_related('pizzas__toppings')
这将预售所有属于餐馆的比萨饼,以及属于这些比萨的所有配料。这将导致总共3个数据库查询--一个用于餐馆,一个用于比萨饼,另一个用于配料。
>>> Restaurant.objects.prefetch_related('best_pizza__toppings')
这将获得最好的比萨饼和所有的配料最好的比萨饼为每家餐厅。这将在3个数据库查询中完成–一个用于餐馆,一个用于“最佳比萨饼”,另一个用于配料。
当然,best_pizza关系也可以使用select_related若要将查询计数减至2,
请执行以下操作:
>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')
因为预取是在主查询之后执行的(这包括select_related),它能够检测到best_pizza对象已经被获取,并且它将再次跳过获取它们。
链子prefetch_related调用将累积预取的查找。清除任何prefetch_related行为,通过None作为参数:
>>> non_prefetched = qs.prefetch_related(None)
使用时要注意的一个不同之处prefetch_related由查询创建的对象可以在与其相关的不同对象之间共享,即单个Python模型实例可以出现在返回对象树的多个点上。这通常会发生在外键关系中。通常,这种行为不会成为问题,实际上将节省内存和CPU时间。
当prefetch_related支持预取GenericForeignKey关系,查询的数量将取决于数据。因为GenericForeignKey可以引用多个表中的数据,每个引用的表需要一个查询,而不是所有项的一个查询。类可能会有其他查询。ContentType如果尚未获取相关行,则为表。
prefetch_related在大多数情况下,将使用使用“IN”操作符的SQL查询来实现。这意味着对于一个大的QuerySet可以生成一个大的‘IN’子句,这取决于数据库,在解析或执行SQL查询时可能会有自己的性能问题。始终为您的用例配置文件!
请注意,如果您使用iterator()
要运行查询,prefetch_related()调用将被忽略,因为这两个优化在一起没有意义。
您可以使用Prefetch对象以进一步控制预取操作。
最简单的形式Prefetch等效于传统的基于字符串的查找:
>>> from django.db.models import Prefetch
>>> Restaurant.objects.prefetch_related(Prefetch('pizzas__toppings'))
可以提供自定义查询集。queryset争论。这可用于更改queryset的默认顺序:
>>> Restaurant.objects.prefetch_related(
... Prefetch('pizzas__toppings', queryset=Toppings.objects.order_by('name')))
或者打电话select_related()在适用时,可进一步减少查询次数:
>>> Pizza.objects.prefetch_related(
... Prefetch('restaurants', queryset=Restaurant.objects.select_related('best_pizza')))
还可以将预取结果分配给带有可选属性的自定义属性。to_attr
。结果将直接存储在列表中。
这允许使用不同的方法多次预取相同的关系。QuerySet;例如:
>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
... Prefetch('pizzas', to_attr='menu'),
... Prefetch('pizzas', queryset=vegetarian_pizzas, to_attr='vegetarian_menu'))
使用自定义创建的查找to_attr其他查找仍然可以像往常一样遍历:
>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
... Prefetch('pizzas', queryset=vegetarian_pizzas, to_attr='vegetarian_menu'),
... 'vegetarian_menu__toppings')
使用to_attr在筛选预取结果时推荐这样做,因为与将筛选结果存储在相关管理器的缓存中相比,预取结果更不含糊:
>>> queryset = Pizza.objects.filter(vegetarian=True)
>>>
>>> # Recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
... Prefetch('pizzas', queryset=queryset, to_attr='vegetarian_pizzas'))
>>> vegetarian_pizzas = restaurants[0].vegetarian_pizzas
>>>
>>> # Not recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
... Prefetch('pizzas', queryset=queryset))
>>> vegetarian_pizzas = restaurants[0].pizzas.all()
自定义预取也适用于单关联关系(如前向)。ForeignKey或OneToOneField…一般情况下你会想用select_related()对于这些关系,但是有许多情况下,使用自定义预取QuerySet是有用的:
您想使用QuerySet对相关模型执行进一步的预取。
您希望只预取相关对象的一个子集。
您希望使用性能优化技术,例如deferred fields:
>>> queryset = Pizza.objects.only('name')
>>>
>>> restaurants = Restaurant.objects.prefetch_related(
... Prefetch('best_pizza', queryset=queryset))
注解
查找的顺序很重要。
以下列例子为例:
>>> prefetch_related('pizzas__toppings', 'pizzas')
即使它是无序的,它也能工作,因为'pizzas__toppings'已经包含了所有需要的信息,因此第二个参数'pizzas'实际上是多余的。
>>> prefetch_related('pizzas__toppings', Prefetch('pizzas', queryset=Pizza.objects.all()))
这会引起ValueError因为试图重新定义以前看到的查找的查询集。注意,创建了一个隐式queryset来遍历’pizzas’作为’pizzas__toppings’查一下。
>>> prefetch_related('pizza_list__toppings', Prefetch('pizzas', to_attr='pizza_list'))
这将触发AttributeError因为'pizza_list'还不存在的时候'pizza_list__toppings'正在处理中。
这一考虑不仅仅限于使用Prefetch。一些高级技术可能要求按照特定的顺序执行查找,以避免创建额外的查询;因此,建议始终小心排序prefetch_related。
extra()¶
extra(选择=无, WHERE=无, Params=无, 表=无, 订单比=无, 选择参数=无)¶
有时,Django查询语法本身并不能很容易地表示复杂的WHERE条款。对于这些边缘情况,Django提供了extra() QuerySet修饰符-用于将特定子句注入由QuerySet.
使用这种方法作为最后的手段
这是一个老API,我们的目标是在将来的某个时候放弃它。只有在不能使用其他queryset方法表示查询时才使用它。如果您需要使用它,请使用它。开罚单使用QuerySet.External关键字使用用例(请先检查现有票证列表),以便我们可以增强QuerySet API以允许删除extra()…我们不再改进或修复这种方法的错误。
例如,使用extra():
>>> qs.extra(
... select={'val': "select col from sometable where othercol = %s"},
... select_params=(someparam,),
... )
相当于:
>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
使用的主要好处RawSQL是你可以output_field如果需要的话。主要缺点是,如果引用原始SQL中queryset的某个表别名,则Django可能会更改该别名(例如,在另一个查询中将queryset用作子查询时)。
警告
当你使用的时候,你应该非常小心。extra()…每次使用它时,都应该通过以下方法转义用户可以控制的任何参数:params以防止SQL注入攻击。
还不能引用SQL字符串中的占位符。由于周围的引号,此示例容易受到sql注入的攻击。%s:
"select col from sometable where othercol = '%s'" # unsafe!
你可以读到更多关于DjangoSQL注入保护起作用了。
根据定义,这些额外的查找可能无法移植到不同的数据库引擎(因为您正在显式编写SQL代码),并且违反了枯燥原则,因此如果可能的话,您应该避免它们。
指定一个或多个params, select, where或tables…不需要任何参数,但至少应该使用其中的一个参数。
select
这个select参数允许在SELECT条款。它应该是将属性名映射到SQL子句以用于计算该属性的字典。
例子:
Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
因此,每个Entry对象将有一个额外的属性,is_recent,一个布尔值,表示条目的pub_date大于2006年1月1日。
Django将给定的SQL片段直接插入到SELECT语句,因此上面示例的结果SQL应该如下所示:
SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent
FROM blog_entry;
下一个示例更高级;它执行一个子查询来给出每个结果Blog对象aentry_count属性,关联的整数计数。Entry物体:
Blog.objects.extra(
select={
'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
},
)
在这种情况下,我们利用了一个事实,即查询已经包含了blog_blog它的表FROM条款。
上述示例的结果SQL为:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count
FROM blog_blog;
注意,大多数数据库引擎在子查询周围所需的括号在Django的select条款。还要注意的是,一些数据库后端(如某些MySQL版本)不支持子查询。
在一些罕见的情况下,您可能希望将参数传递给extra(select=…)…为此,请使用select_params参数。自select_params是一个序列,而select属性是一个字典,需要一定的注意,以便将参数与额外的选择片段正确匹配。在这种情况下,您应该使用collections.OrderedDict为select值,而不仅仅是普通的Python字典。
这将起作用,例如:
Blog.objects.extra(
select=OrderedDict([('a', '%s'), ('b', '%s')]),
select_params=('one', 'two'))
如果您需要使用文字%s在选择字符串中,使用序列%%s.
where / tables
可以定义显式sql。WHERE子句–可能是执行非显式联接–使用where…可以手动将表添加到sql中。FROM从句tables.
where和tables
两个人都有一个字符串列表。全where参数是“和”到任何其他搜索标准。
例子:
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
.将(大致)转换为以下SQL:
SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
使用tables参数,如果指定查询中已经使用的表,则为。当您通过tables参数时,Django假设您希望该表包含额外的时间(如果它已经包括在内)。这就产生了一个问题,因为表名随后将被赋予一个别名。如果一个表在SQL语句中多次出现,则第二次和以后发生的事件必须使用别名,这样数据库才能区分它们。如果您指的是在额外表中添加的额外表where参数,这将导致错误。
通常,您将只添加没有出现在查询中的额外表。但是,如果确实出现上述情况,则有几种解决方案。首先,看看您是否可以在不包括额外表的情况下过活,并使用查询中已经存在的表。如果那是不可能的,把你的extra()调用queryset构造的前面,以便您的表是该表的第一次使用。最后,如果所有这些都失败了,请查看生成的查询并重写where额外使用给您的额外表的别名。每次以相同的方式构造queryset时,别名都是相同的,因此可以依赖别名不更改。
order_by
如果您需要使用您所包含的一些新字段或表对结果查询集进行排序,请通过extra()使用order_by参数extra()然后传递一串字符串。这些字符串应该是模型字段(如正常的)。order_by()方法的table_name.column_name中指定的列的别名。select参数extra().
例如:
q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
q = q.extra(order_by = ['-is_recent'])
这将对下列所有项目进行排序:is_recent与结果集的前面一致(True排序前False按降序排列)。
顺便说一句,这表明您可以拨打多个电话。extra()并且它将按照您的预期运行(每次添加新的约束)。
params
这个where参数可以使用标准Python数据库字符串占位符-’%s’要指示参数,数据库引擎应该自动引用。这个params参数是要替换的任何额外参数的列表。
例子:
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
总用params而不是将值直接嵌入到where因为params将确保根据您的特定后端正确引用值。例如,引号将正确转义。
坏:
Entry.objects.extra(where=["headline='Lennon'"])
好:
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
警告
如果在MySQL上执行查询,请注意MySQL的无声类型强制在混合类型时可能会导致意外的结果。如果查询字符串类型列,但使用整数值,MySQL将在执行比较之前强制将表中所有值的类型转换为整数。例如,如果表包含值’abc’, 'def’你要查询WHERE mycolumn=0,两行将匹配。若要防止这种情况,请在使用查询中的值之前执行正确的类型转换。
defer()¶
defer(*字段)¶
在一些复杂的数据建模情况下,您的模型可能包含许多字段,其中一些字段可能包含大量数据(例如,文本字段),或者需要昂贵的处理才能将它们转换为Python对象。如果在某些情况下使用查询集的结果,在最初获取数据时不知道是否需要这些特定字段,则可以告诉Django不要从数据库中检索这些字段。
这是通过传递要不加载的字段的名称来完成的。defer():
Entry.objects.defer("headline", "body")
具有延迟字段的查询集仍将返回模型实例。如果您访问该字段(每次访问一个字段,而不是同时访问所有延迟字段),则将从数据库检索每个延迟字段。
您可以拨打多个电话到defer()…每个调用都会向延迟集合添加新字段:
# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")
将字段添加到延迟集的顺序并不重要。呼叫defer()对于一个已经被推迟的字段名是无害的(该字段仍将被延迟)。
您可以延迟加载相关模型中的字段(如果相关模型是通过select_related())使用标准的双下划线符号分隔相关字段:
Blog.objects.select_related().defer("entry__headline", "entry__body")
如果要清除一组延迟字段,请传递None作为参数defer():
# Load all fields immediately.
my_queryset.defer(None)
模型中的某些字段不会被延迟,即使您要求它们。您永远不能推迟主键的加载。如果你用select_related()
要检索相关模型,不应该延迟从主模型连接到相关模型的字段的加载,这样做会导致错误。
注解
这个defer()方法(以及它的表亲,only())只适用于高级用例。当您仔细分析查询并理解时,它们提供了一个优化。一点儿没错您需要并已经测量到的信息是,返回所需字段与模型的全部字段集之间的差异将是显著的。
即使你认为你处在高级用例的情况下,仅在不能在queryset加载时使用Date()来确定是否需要额外的字段…如果您经常加载和使用特定的数据子集,您可以做出的最佳选择是将模型规范化,并将未加载的数据放入单独的模型(和数据库表)中。如果列必由于某种原因,请留在一个表中,创建一个模型Meta.managed = False(见managed attribute(文档)只包含通常需要加载和使用的字段,否则可能会调用这些字段。defer()…这使您的代码对读者更加明确,在Python过程中稍微快了一点,占用的内存也少了一点。
例如,这两种模型都使用相同的底层数据库表:
class CommonlyUsedModel(models.Model):
f1 = models.CharField(max_length=10)
class Meta:
managed = False
db_table = 'app_largetable'
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
db_table = 'app_largetable'
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.all().defer('f2')
如果需要在非托管模型中复制许多字段,最好使用共享字段创建抽象模型,然后让非托管和托管模型继承抽象模型。
注解
only()¶
只(*字段)¶
这个only()方法或多或少是相反的。defer()…你用应该不在检索模型时被推迟。如果您有一个模型,其中几乎所有字段都需要延迟,则使用only()要指定互补的字段集,可能会产生更简单的代码。
假设您有一个带字段的模型name, age和biography…以下两个查询集在延迟字段方面是相同的:
Person.objects.defer("age", "biography")
Person.objects.only("name")
每当你打电话only()它取代要立即加载的字段集。该方法的名称是助记符:只这些字段将立即加载;其余字段将被延迟。因此,连续调用only()结果只有正在审议的最后领域:
# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")
自defer()递增(将字段添加到延迟列表),可以将调用合并到only()和defer()事情会有逻辑的:
# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")
# Final result loads headline and body immediately (only() replaces any
# existing set of fields).
Entry.objects.defer("body").only("headline", "body")
注意事项的所有注意事项defer()文件适用于only()也是。小心使用它,只有在用尽了其他选择之后。
使用only()并删除请求的字段。select_related()也是个错误。
using()¶
using(化名)¶
此方法用于控制QuerySet如果您正在使用多个数据库,
则将对其进行评估。此方法所使用的唯一参数是数据库的别名,如DATABASES.
例如:
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')
select_for_update()¶
select_for_update(NoWait=false, 跳过锁定=假, of=())¶
返回一个查询集,该查询集将锁定行直到事务结束,从而生成一个SELECT ... FOR UPDATE支持的数据库上的SQL语句
。
例如:
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
当计算查询集时(for entry in entries在这种情况下,所有匹配的条目都将被锁定,直到事务块结束,这意味着其他事务将被阻止更改或获取对它们的锁。
通常,如果另一个事务已经获得选定行之一的锁,则查询将被阻塞,直到锁被释放。如果这不是你想要的行为,打电话给select_for_update(nowait=True)...这将使呼叫非阻塞。
如果冲突锁已被另一个事务获取,DatabaseError将在计算查询集时引发。还可以通过以下方法忽略锁定的行:select_for_update(skip_locked=True)
相反。这个nowait和skip_locked是相互排斥的,并试图调用select_for_update()
如果启用了这两个选项,则将导致ValueError.
默认情况下,例如,在select_related()除了Queryset模型的行之外,还会锁定。如果不想这样做,请指定要锁定的相关对象。select_for_update(of=(…))使用与select_related()…使用值’self’引用Queryset的模型。
你不能用select_for_update()关于可无法律关系:
>>> Person.objects.select_related('hometown').select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join
为了避免这种限制,如果您不关心空对象,可以排除它们:
>>> Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
目前,postgresql, oracle,和mysql数据库后端支持select_for_update()...
但是,MySQL不支持nowait, skip_locked,
和of。
过路nowait=True, skip_locked=True,或of到select_for_update()使用不支持这些选项的数据库后端(例如MySQL)会引发NotSupportedError…这样可以防止代码意外阻塞。
使用select_for_update()在支持后端的自动提交模式中SELECT … FOR UPDATE是TransactionManagementError错误,因为在这种情况下,行没有被锁定。如果允许的话,这将助长数据损坏,并且很容易由于调用期望在事务之外的事务中运行的代码而引起。
使用select_for_update()在不支持的后端上SELECT … FOR UPDATE(如SQLite)将没有任何效果。SELECT … FOR UPDATE将不会添加到查询中,并且在下列情况下不会引发错误select_for_update()在自动提交模式中使用。
警告
尽管select_for_update()通常在自动提交模式下失败,因为TestCase在事务中自动包装每个测试,调用select_for_update()在.TestCase即使在atomic()块将(可能意外地)通过而不引发TransactionManagementError…正确测试select_for_update()你应该用TransactionTestCase.
raw()¶
raw(原始查询, Params=无, 翻译=无)¶
获取原始SQL查询,执行该查询,并返回django.db.models.query.RawQuerySet
举个例子。这RawQuerySet实例可以像普通的一样迭代。QuerySet提供对象实例。
见执行原始SQL查询想了解更多信息。
raw()总是触发一个新的查询,而不考虑以前的筛选。
因此,通常应该从Manager或是新鲜的QuerySet举个例子。
返回新运算符QuerySets¶
组合查询集必须使用相同的模型。
和(&)¶
结合二QuerySets使用sql。AND接线员。
以下内容相当于:
Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) & Q(y=2))
SQL等效:
SELECT ... WHERE x=1 AND y=2
或(|)¶
结合二QuerySets使用sql。OR接线员。
以下内容相当于:
Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))
SQL等效:
SELECT ... WHERE x=1 OR y=2
不返回的方法。QuerySets¶
以下内容QuerySet方法评价QuerySet还东西除 a QuerySet.
这些方法不使用缓存(请参阅缓存和查询集)。相反,每次调用时,他们都会查询数据库。
get()¶
get(**)¶
返回与给定查找参数匹配的对象,这些参数应以字段查找.
get()提高MultipleObjectsReturned如果找到多个对象。这个MultipleObjectsReturned异常是模型类的属性。
get()提出DoesNotExist如果未为给定参数找到对象,则为例外。此异常是模型类的属性。例子:
Entry.objects.get(id='foo') # raises Entry.DoesNotExist
这个DoesNotExist异常继承自django.core.exceptions.ObjectDoesNotExist,这样您就可以针对多个DoesNotExist例外。例子:
from django.core.exceptions import ObjectDoesNotExist
try:
e = Entry.objects.get(id=3)
b = Blog.objects.get(id=1)
except ObjectDoesNotExist:
print("Either the entry or blog doesn't exist.")
如果希望查询集返回一行,则可以使用get()没有任何参数来返回该行的对象:
entry = Entry.objects.filter(...).exclude(...).get()
create()¶
create(**)¶
一种创建对象并在一步内全部保存的方便方法。因此:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
以及:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
都是等价物。
这个力片参数在其他地方有文档记录,但这意味着将始终创建一个新对象。通常你不需要担心这个。但是,如果您的模型包含您设置的手动主键值,如果该值已经存在于数据库中,则调用create()将失败IntegrityError因为主键必须是唯一的。如果您使用的是手动主键,请做好处理异常的准备。
get_or_create()¶
get_or_create(默认值=无, **)¶
查找对象的一种方便方法kwargs(如果模型对所有字段都有默认值,则可能为空),必要时创建一个字段。
返回元组(object, created),在哪里object是检索或创建的对象,created指定是否创建了新对象的布尔值。
这意味着作为boilerplatish代码的快捷方式。例如:
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()
随着模型中字段数量的增加,这种模式变得非常笨拙。上面的示例可以使用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() — 除一个可选的名为defaults-将用于get()打电话。如果找到一个物体,get_or_create()返回该对象的元组,并且False.
可以通过链接为检索到的对象指定更复杂的条件。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…如果对象是不被发现,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评估它们。正如上面所暗示的,这是对所使用的算法的简化,但是它包含了所有相关的细节。内部实现有更多的错误检查,并处理一些额外的边缘条件;如果您感兴趣,请阅读代码。
如果您有一个名为defaults并希望将其用作get_or_create(),就用’defaults__exact’,就像这样:
Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
这个get_or_create()方法具有类似的错误行为。create()当您使用手动指定的主键时。如果需要创建一个对象,并且数据库中的键已经存在,则IntegrityError将被提升。
此方法是原子化的,假定正确的使用、正确的数据库配置和基础数据库的正确行为。但是,如果没有在数据库级别强制执行kwargs用于get_or_create打电话(见unique或unique_together),该方法容易出现竞争条件,从而导致同时插入相同参数的多行。
如果您正在使用MySQL,请确保使用READ COMMITTED隔离级别而不是REPEATABLE READ(默认值),否则您可能会看到get_or_create将引发IntegrityError但是对象不会出现在后续的get()打电话。
最后,一个关于使用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)
你可以用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
之所以发生这种情况,是因为它试图通过“尤利西斯”一书获得或创建“第一章”,但其中任何一本都做不到:关系无法获取该章节,因为它与那本书无关,但它也不能创建它,因为title字段应该是唯一的。
update_or_create()¶
update_or_create(默认值=无, **)¶
对象更新的一种方便的方法。kwargs,必要时创建一个新的。这个defaults用于更新对象的(字段、值)对的字典。中的值defaults可以是可调用的。
返回元组(object, created),
在哪里object是已创建或更新的对象,created指定是否创建了新对象的布尔值。
这个update_or_create方法尝试从数据库中获取对象。kwargs…如果找到匹配项,则更新defaults字典。
这意味着作为boilerplatish代码的快捷方式。例如:
defaults = {'first_name': 'Bob'}
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
new_values = {'first_name': 'John', 'last_name': 'Lennon'}
new_values.update(defaults)
obj = Person(**new_values)
obj.save()
随着模型中字段数量的增加,这种模式变得非常笨拙。上面的示例可以使用update_or_create()就像这样:
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon',
defaults={'first_name': 'Bob'},
)
有关名称如何传入的详细说明kwargs已解决,请参见get_or_create().
如上文所述,在get_or_create(),此方法容易出现竞争条件,如果在数据库级别不强制执行唯一性,则会同时插入多个行。
喜欢get_or_create()和create(),如果您正在使用手动指定的主键,并且需要创建一个对象,但数据库中已经存在该键,则IntegrityError已经长大了。
bulk_create()¶
bulk_create(奥比斯, 批次大小=无)¶
该方法以有效的方式将提供的对象列表插入数据库(通常只有一个查询,不管有多少对象):
>>> Entry.objects.bulk_create([
... Entry(headline='This is a test'),
... Entry(headline='This is only a test'),
... ])
尽管如此,这还是有一些注意事项:
模型的save()方法将不会被调用,并且pre_save和post_save信号不会发送。
它不适用于多表继承场景中的子模型。
如果模型的主键是AutoField它不检索和设置主键属性,如save(),除非数据库后端支持它(目前是PostgreSQL)。
它不适用于多到多的关系。
它铸造奥比斯到一个列表中,该列表将完整地计算出奥比斯如果是发电机的话。强制转换允许检查所有对象,以便可以首先插入具有手动设置主键的任何对象。如果希望在不立即计算整个生成器的情况下批量插入对象,则只要对象没有手动设置主键,就可以使用此技术:
from itertools import islice
batch_size = 100
objs = (Entry(headline='Test %s' % i) for i in range(1000))
while True:
batch = list(islice(objs, batch_size))
if not batch:
break
Entry.objects.bulk_create(batch, batch_size)
这个batch_size参数控制在单个查询中创建了多少个对象。默认情况是在一个批处理中创建所有对象,但SQLite除外,默认情况下,每个查询最多使用999个变量。
count()¶
count()¶
返回一个整数,表示数据库中匹配QuerySet.
例子:
# Returns the total number of entries in the database.
Entry.objects.count()
# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains='Lennon').count()
A count()调用执行一个SELECT COUNT(*)在幕后,所以你应该经常使用count()而不是将所有记录加载到Python对象并调用len()结果(除非您需要将对象加载到内存中,在这种情况下)len()会更快)。
注意,如果要在QuerySet并且还从它检索模型实例(例如,通过迭代它),使用它可能更有效len(queryset)这不会导致额外的数据库查询,例如count()会的。
in_bulk()¶
in_bulk(ID_List=无, 字段名=‘pk’)¶
获取字段值列表(id_list)和字段名对于这些值,并返回一个字典,将每个值映射到具有给定字段值的对象实例。如果id_list不提供,则返回查询集中的所有对象。字段名必须是唯一的字段,它默认为主键。
例子:
>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(['beatles_blog'], field_name='slug')
{'beatles_blog': <Blog: Beatles Blog>}
iterator()¶
iterator(块体尺寸=2000)¶
评估QuerySet(通过执行查询)并返回迭代器(请参见佩普234)超过结果。一个QuerySet通常在内部缓存其结果,以便重复的评估不会导致额外的查询。相反,iterator()将直接读取结果,而无需在QuerySet级别(内部,默认迭代器调用iterator()并缓存返回值)。为了QuerySet它返回大量只需访问一次的对象,这可能会带来更好的性能和显着地减少内存。
注意,使用iterator()在.上QuerySet它将迫使它再次计算,重复查询。
此外,使用iterator()前因prefetch_related()调用将被忽略,因为这两个优化在一起没有意义。
根据数据库后端的不同,查询结果要么一次性加载,要么使用服务器端游标从数据库流。
带有服务器端游标¶
甲骨文和PostgreSQL使用服务器端游标来流来自数据库的结果,而不将整个结果集加载到内存中。
Oracle数据库驱动程序总是使用服务器端游标.
使用服务器端游标,则chunk_size参数指定要在数据库驱动程序级别缓存的结果数。获取更大的块会减少数据库驱动程序和数据库之间的往返次数,而牺牲内存。
在PostgreSQL上,服务器端游标仅在DISABLE_SERVER_SIDE_CURSORS设置是False…朗读事务池和服务器端游标如果您使用的是在事务池模式中配置的连接池程序。当禁用服务器端游标时,这种行为与不支持服务器端游标的数据库相同.
没有服务器端游标¶
MySQL和SQLite不支持流结果,因此Python数据库驱动程序将整个结果集加载到内存中。然后,数据库适配器使用fetchmany()中定义的方法。佩普249.
这个chunk_size参数控制从数据库驱动程序中检索的批处理Django的大小。更大的批处理减少了与数据库驱动程序通信的开销,而牺牲了内存消耗的小幅增加。
的默认值chunk_size,2000年,来自精神科邮件列表的计算:
假设有10到20列的行混合了文本数据和数字数据,2000年将获取不到100 kb的数据,如果循环提前退出,这似乎是在传输的行数和丢弃的数据之间的一个很好的折衷。
latest()¶
latest(*字段)¶
根据给定字段返回表中的最新对象。
此示例返回最新的Entry在表中,根据pub_date字段:
Entry.objects.latest('pub_date')
您还可以根据几个字段选择最新的。例如,若要选择Entry最早expire_date当两个条目具有相同的pub_date:
Entry.objects.latest('pub_date', '-expire_date')
负号’-expire_date’分类手段expire_date在……里面降秩序。自latest()获取最后一个结果,Entry最早expire_date被选中。
如果你的模特元指定get_latest_by,您可以省略任何参数earliest()或latest()…中指定的字段。get_latest_by默认情况下使用。
喜欢get(), earliest()和latest()提高DoesNotExist如果没有具有给定参数的对象。
请注意earliest()和latest()存在纯粹是为了方便和可读性。
earliest()和latest()可能返回空日期的实例。
由于将排序委托给数据库,如果使用不同的数据库,允许空值的字段的排序可能会有所不同。例如,PostgreSQL和MySQL对空值进行排序,就好像它们高于非空值一样,而SQLite则相反。
您可能希望筛选出空值:
Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
earliest()¶
earliest(*字段)¶
不然就像latest()只是方向改变了。
first()¶
first()¶
返回由queryset匹配的第一个对象,或None如果没有匹配的对象。如果QuerySet没有定义排序,则查询集由主键自动排序。这可能会影响聚合结果,如与默认排序或Order_by()的交互.
例子:
p = Article.objects.order_by('title', 'pub_date').first()
请注意first()是一种方便的方法,下面的代码示例等效于上面的示例:
try:
p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
p = None
last()¶
last()¶
就像first(),但返回查询集中的最后一个对象。
aggregate()¶
aggregate(*ARGS, **)¶
返回聚合值的字典(平均值、和等)
在QuerySet…每一个论点aggregate()指定将包含在返回的字典中的值。
Django提供的聚合函数在聚合函数下面。因为聚合体也是查询表达式,您可以将聚合与其他聚合或值组合起来,以创建复杂聚合。
使用关键字参数指定的聚合将使用关键字作为注释的名称。匿名参数将根据聚合函数的名称和正在聚合的模型字段为它们生成一个名称。复杂聚合不能使用匿名参数,必须将关键字参数指定为别名。
例如,在处理博客条目时,您可能想知道有多少作者提供了博客条目:
>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}
通过使用关键字参数指定聚合函数,可以控制返回的聚合值的名称:
>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}
exists()¶
exists()¶
回报True如果QuerySet包含任何结果,以及False如果不是。这试图以最简单和最快的方式执行查询,但它是吗?执行与普通查询几乎相同的查询。QuerySet查询。
exists()中的两个对象成员关系的搜索非常有用。
QuerySet中的任何对象的存在。QuerySet,特别是在大型QuerySet.
最有效的方法,以确定一个模型是否有一个唯一的字段。primary_key)是QuerySet是:
entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
print("Entry contained in queryset")
它将比需要对整个查询集进行计算和迭代的以下操作更快:
if entry in some_queryset:
print("Entry contained in QuerySet")
若要查找查询集是否包含任何项,请执行以下操作:
if some_queryset.exists():
print("There is at least one object in some_queryset")
其速度将超过:
if some_queryset:
print("There is at least one object in some_queryset")
…但并不是很大程度上(因此需要一个大的查询集来提高效率)。
此外,如果some_queryset还没有被评估,但是您知道它在某个时候会被评估,然后使用some_queryset.exists()将完成更全面的工作(对存在性检查进行一次查询,然后再进行一次额外的查询以检索结果),而不仅仅是使用bool(some_queryset),它检索结果,然后检查是否返回任何结果。
update()¶
update(**)¶
对指定字段执行SQL更新查询,并返回匹配的行数(如果某些行已经具有新值,则可能不等于已更新的行数)。
例如,要关闭2010年发布的所有博客条目的评论,可以这样做:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
(这假设您的Entry模型有字段pub_date和comments_on.)
您可以更新多个字段-没有多少限制。例如,这里我们更新comments_on和headline字段:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')
这个update()方法立即应用,并且对QuerySet更新后的内容是,它只能更新模型主表中的列,而不能更新相关模型上的列。你不能这样做,例如:
>>> Entry.objects.update(blog__name='foo') # Won't work!
但是,基于相关字段的筛选仍然是可能的:
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
你不能打电话update()在.上QuerySet已经取了一片,否则就不能再过滤了。
这个update()方法返回受影响的行数:
>>> Entry.objects.filter(id=64).update(comments_on=True)
1
>>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True)
0
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132
如果您只是在更新记录,而不需要对模型对象做任何事情,那么最有效的方法就是调用update(),而不是将模型对象加载到内存中。例如,没有这样做:
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
.做这个
Entry.objects.filter(id=10).update(comments_on=False)
使用update()还可以防止在加载对象和调用之间的短时间内数据库中的某些内容可能发生更改的争用条件。save().
最后,要意识到update()在sql级别进行更新,因此不调用任何save()方法,也不会发出pre_save或post_save信号(这是呼叫的结果)Model.save())。如果要更新具有自定义的模型的一组记录save()方法,循环它们并调用save(),就像这样:
for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
delete()¶
delete()¶
对象中的所有行执行sql删除查询。QuerySet并返回已删除对象的数量和每个对象类型删除次数的字典。
这个delete()立即应用。你不能打电话delete()在.上QuerySet已经取了一片,否则就不能再过滤了。
例如,要删除特定博客中的所有条目:
>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'weblog.Entry': 2, 'weblog.Entry_authors': 2})
默认情况下,Django‘sForeignKey模拟sql约束。ON DELETE CASCADE-换句话说,任何带有外键指向要删除的对象的对象都将与这些对象一起删除。
例如:
>>> blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'weblog.Blog': 1, 'weblog.Entry': 2, 'weblog.Entry_authors': 2})
此级联行为可通过on_delete对ForeignKey.
这个delete()方法执行大容量删除,而不调用任何delete()你的模型上的方法。但是,它确实会发出pre_delete和post_delete所有已删除对象的信号(包括级联删除)。
Django需要将对象提取到内存中,以发送信号和处理级联。但是,如果没有级联和信号,则Django可以采用快速路径并删除对象,而不需要将其提取到内存中。对于大型删除,这可能导致显着减少内存使用。执行查询的数量也可以减少。
设置为on_delete DO_NOTHING不要阻止在删除中采取快速路径.
as_manager()¶
类方法as_manager()¶
类方法,该方法返回Manager带着一份QuerySet的方法。看见使用QuerySet方法创建管理器更多细节。
explain()¶
在Django新设2.1:
explain(格式=无, **备选方案)¶
返回QuerySet的执行计划,详细说明数据库将如何执行查询,包括将使用的任何索引或联接。了解这些细节可能有助于提高慢速查询的性能。
例如,在使用PostgreSQL时:
>>> print(Blog.objects.filter(title='My Blog').explain())
Seq Scan on blog (cost=0.00..35.50 rows=10 width=12)
Filter: (title = 'My Blog'::bpchar)
数据库之间的输出差别很大。
explain()所有内置数据库后端都支持,但Oracle除外,因为那里的实现并不简单。
这个format参数更改数据库默认的输出格式,通常是基于文本的。PostgreSQL支持’TEXT’, ‘JSON’, ‘YAML’,和’XML’…MySQL支持’TEXT’(亦称’TRADITIONAL’)和’JSON’.
一些数据库接受可以返回有关查询的更多信息的标志。将这些标志作为关键字参数传递。例如,在使用PostgreSQL时:
>>> print(Blog.objects.filter(title='My Blog').explain(verbose=True))
Seq Scan on public.blog (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
Output: id, title
Filter: (blog.title = 'My Blog'::bpchar)
Planning time: 0.064 ms
Execution time: 0.058 ms
在某些数据库上,标志可能导致执行查询,这可能会对数据库产生不利影响。例如,PostgreSQL的ANALYZE如果存在触发器或调用函数,则会导致对数据的更改,即使对于SELECT查询。
Field查找¶
字段查找是如何指定sql的内容的。WHERE条款。它们被指定为QuerySet方法filter(), exclude()和get().
有关介绍,请参见模型和数据库查询文档.
Django的内置查找如下所示。也可以写自定义查找模型字段。
在不提供查找类型时(如Entry.objects.get(id=14))假定查找类型为exact.
exact¶
完全吻合。
如果为比较提供的值是None,它将被解释为sql。NULL(见isnull了解更多细节)。
例子:
Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)
SQL等效项:
SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;
MySQL比较
在MySQL中,数据库表的“排序规则”设置确定exact比较是区分大小写的。
这是一个数据库设置,不一个Django设置。可以将MySQL表配置为使用区分大小写的比较,但需要进行一些权衡。有关此问题的详细信息,请参阅校对科在数据库文件。
iexact¶
不区分大小写的精确匹配。
如果为比较提供的值是None,它将被解释为sql。NULL(见isnull了解更多细节)。
例子:
Blog.objects.get(name__iexact='beatles blog')
Blog.objects.get(name__iexact=None)
SQL等效项:
SELECT ... WHERE name ILIKE 'beatles blog';
SELECT ... WHERE name IS NULL;
注意,第一个查询将匹配’Beatles Blog’, ‘beatles blog’, 'BeAtLes BLoG’等
SQLite用户
在使用SQLite后端和非ASCII字符串时,请记住数据库注释关于字符串比较。SQLite不对非ASCII字符串执行不区分大小写的匹配。
contains¶
区分大小写
的安全壳测试。
例子:
Entry.objects.get(headline__contains='Lennon')
SQL等效:
SELECT ... WHERE headline LIKE '%Lennon%';
注:这将与标题匹配。'Lennon honored today'但不是'lennon honored today'.
SQLite用户
SQLite不支持区分大小写的LIKE发言;contains表现得像icontains为了SQLite。见数据库注释想了解更多信息。
icontains¶
箱形不敏感安全壳试验。
例子:
Entry.objects.get(headline__icontains='Lennon')
SQL等效:
SELECT ... WHERE headline ILIKE '%Lennon%';
SQLite用户
在使用SQLite后端和非ASCII字符串时,请记住数据库注释关于字符串比较。
in¶
在给定的可迭代性中;通常是列表、元组或查询集。这不是一个常见的用例,但是字符串(是可迭代的)是可以接受的。
例子:
Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in='abc')
SQL等效项:
SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');
还可以使用查询集动态计算值列表,
而不是提供文字值列表:
inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)
这个查询集
将被计算为子SELECT语句:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
如果你通过QuerySet产生于values()或values_list()作为__in查找时,需要确保只提取结果中的一个字段。例如,这将起作用(过滤博客名称):
inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)
此示例将引发异常,因为内部查询试图提取两个字段值,其中只有一个是预期的:
# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)
业绩考虑
在使用嵌套查询时要小心,并了解数据库服务器的性能特征(如果有疑问,请进行基准测试!)一些数据库后端,特别是MySQL,并不能很好地优化嵌套查询。在这种情况下,提取一个值列表并将其传递到第二个查询中会更有效。也就是说,执行两个查询而不是一个查询:
values = Blog.objects.filter(
name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))
注意list()给博客打电话QuerySet强制执行第一个查询。如果没有它,将执行嵌套查询,因为QuerySet很懒.
gt¶
比。
例子:
Entry.objects.filter(id__gt=4)
SQL等效:
SELECT ... WHERE id > 4;
gte¶
大于或等于。
lt¶
少于。
lte¶
小于或等于。
startswith¶
区分大小写。
例子:
Entry.objects.filter(headline__startswith='Lennon')
SQL等效:
SELECT ... WHERE headline LIKE 'Lennon%';
SQLite不支持区分大小写的LIKE发言;startswith表现得像istartswith为了SQLite。
istartswith¶
不区分大小写。
例子:
Entry.objects.filter(headline__istartswith='Lennon')
SQL等效:
SELECT ... WHERE headline ILIKE 'Lennon%';
SQLite用户
在使用SQLite后端和非ASCII字符串时,请记住数据库注释关于字符串比较。
endswith¶
区分大小写的结尾。
例子:
Entry.objects.filter(headline__endswith='Lennon')
SQL等效:
SELECT ... WHERE headline LIKE '%Lennon';
SQLite用户
SQLite不支持区分大小写的LIKE发言;endswith表现得像iendswith为了SQLite。参考数据库注释更多的文档。
iendswith¶
不区分大小写的结尾。
例子:
Entry.objects.filter(headline__iendswith='Lennon')
SQL等效:
SELECT ... WHERE headline ILIKE '%Lennon'
SQLite用户
在使用SQLite后端和非ASCII字符串时,请记住数据库注释关于字符串比较。
range¶
范围
测试(包括)。
例子:
import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))
SQL等效:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
你可以用range任何你可以使用的地方BETWEEN在SQL中-用于日期、数字甚至字符。
警告
过滤aDateTimeField日期将不包括最后一天的项目,因为边界被解释为“在给定日期上的0am”。如果pub_date是DateTimeField,上述表达式将转换为以下SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
一般来说,你不能把日期和约会时间混为一谈。
date¶
对于datetime字段,将值转换为Date。允许链接其他字段查找。取日期值。
例子:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
(此查找没有包含等效的SQL代码片段,因为相关查询的实现在不同的数据库引擎中有所不同。)
什么时候USE_TZ是True,字段在筛选之前转换为当前时区。
year¶
对于日期和日期时间字段,精确的年份匹配。允许链接其他字段查找。需要一个整数年。
例子:
Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)
SQL等效:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
SELECT ... WHERE pub_date >= '2005-01-01';
(每个数据库引擎的确切SQL语法不同。)
什么时候USE_TZ是True,则在筛选之前将日期时间字段转换为当前时区。
month¶
对于日期和日期时间字段,精确的月份匹配。允许链接其他字段查找。取整数1(1月)至12(12月)。
例子:
Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)
SQL等效:
SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';
(每个数据库引擎的确切SQL语法不同。)
什么时候USE_TZ是True,则在筛选之前将日期时间字段转换为当前时区。这需要数据库中的时区定义.
day¶
对于日期和日期时间字段,精确的日期匹配。允许链接其他字段查找。需要一个整数天。
例子:
Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)
SQL等效:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
(每个数据库引擎的确切SQL语法不同。)
注意,这将与该月的第三天的PUB_DATE相匹配,例如1月3日、7月3日等。
什么时候USE_TZ是True,则在筛选之前将日期时间字段转换为当前时区。这需要数据库中的时区定义.
week¶
对于日期和日期时间字段,根据以下内容返回周号(1-52或53)ISO-8601也就是说,周从星期一开始,第一周包含一年的第一个星期四。
例子:
Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
(此查找没有包含等效的SQL代码片段,因为相关查询的实现在不同的数据库引擎中有所不同。)
什么时候USE_TZ是True,字段在筛选之前转换为当前时区。
week_day¶
对于日期和日期时间字段,为“一周中的一天”匹配。允许链接其他字段查找。
取一个整数值,表示从1(星期日)到7(星期六)的一周中的一天。
例子:
Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)
(此查找没有包含等效的SQL代码片段,因为相关查询的实现在不同的数据库引擎中有所不同。)
注意,这将使任何记录与pub_date它落在星期一(一周的第二天),而不管它发生的月份或年份。周日被编入索引,第一天是星期日,第七天是星期六。
什么时候USE_TZ是True,则在筛选之前将日期时间字段转换为当前时区。这需要数据库中的时区定义.
quarter¶
Django 2.0新版本:
对于日期和日期时间字段,“一年中的四分之一”匹配。允许链接其他字段查找。取1到4之间的整数值,表示一年中的第四季度。
示例检索第二季度(4月1日至6月30日)的条目:
Entry.objects.filter(pub_date__quarter=2)
(此查找没有包含等效的SQL代码片段,因为相关查询的实现在不同的数据库引擎中有所不同。)
什么时候USE_TZ是True,则在筛选之前将日期时间字段转换为当前时区。这需要数据库中的时区定义.
time¶
对于datetime字段,将值转换为time。允许链接其他字段查找。采取datetime.time价值。
例子:
Entry.objects.filter(pub_date__time=datetime.time(14, 30))
Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(此查找没有包含等效的SQL代码片段,因为相关查询的实现在不同的数据库引擎中有所不同。)
什么时候USE_TZ是True,字段在筛选之前转换为当前时区。
hour¶
对于日期、时间和时间字段,精确匹配时间。允许链接其他字段查找。取0到23之间的整数。
例子:
Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)
SQL等效:
SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';
(每个数据库引擎的确切SQL语法不同。)
对于日期时间字段,当USE_TZ是True,则在筛选之前将值转换为当前时区。
minute¶
对于日期、时间和时间字段,精确匹配。允许链接其他字段查找。取0到59之间的整数。
例子:
Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)
SQL等效:
SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';
(每个数据库引擎的确切SQL语法不同。)
对于日期时间字段,当USE_TZ是True,则在筛选之前将值转换为当前时区。
second¶
对于日期、时间和时间字段,第二个完全匹配。允许链接其他字段查找。取0到59之间的整数。
例子:
Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)
SQL等效:
SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';
(每个数据库引擎的确切SQL语法不同。)
对于日期时间字段,当USE_TZ是True,则在筛选之前将值转换为当前时区。
isnull¶
取True或False的SQL查询。IS NULL和IS NOT NULL分别。
例子:
Entry.objects.filter(pub_date__isnull=True)
SQL等效:
SELECT ... WHERE pub_date IS NULL;
regex¶
区分大小写的正则表达式匹配。
正则表达式语法是正在使用的数据库后端的语法。对于没有内置正则表达式支持的SQLite,此特性由(Python)用户定义的REGEXP函数提供,因此正则表达式语法是Python的re模块。
例子:
Entry.objects.get(title__regex=r'^(An?|The) +')
SQL等效项:
SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL
SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle
SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL
SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
使用原始字符串(例如,r’foo’而不是’foo’)用于传递正则表达式语法。
iregex¶
不区分大小写的正则表达式匹配。
例子:
Entry.objects.get(title__iregex=r'^(an?|the) +')
SQL等效项:
SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL
SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle
SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL
SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
聚合函数¶
Django在django.db.models模块。有关如何使用这些聚合函数的详细信息,请参阅关于聚合的主题指南…见Aggregate了解如何创建聚合的文档。
警告
SQLite无法立即处理日期/时间字段上的聚合。这是因为SQLite中没有本机日期/时间字段,Django目前使用文本字段模拟这些特性。尝试在SQLite中的日期/时间字段上使用聚合将引发NotImplementedError.
注
聚合函数返回None当与空词连用时QuerySet…例如,Sum聚合函数返回None而不是0如果QuerySet不包含任何条目。例外是Count,它确实会返回0如果QuerySet是空的。
所有聚合体都有以下共同参数:
expressions¶
引用模型上字段的字符串,或查询表达式.
output_field¶
表示模型场返回值
注解
组合多个字段类型时,Django只能确定output_field如果所有字段都是相同类型的。否则,您必须提供output_field你自己。
function filter() { [native code] }¶
Django 2.0新版本:
任选Q object用于过滤聚合的行。
看见条件聚合和对注解的过滤例如使用。
**额外¶
关键字参数,可以为聚合生成的SQL提供额外的上下文。
Avg¶
班级Avg(表达, 输出字段=FloatField(), 过滤器=无, **额外)[源代码]¶
返回给定表达式的平均值,除非您指定了不同的表达式,否则该表达式必须是数字的。output_field.
默认别名:__avg
返回类型:float(或任何类型的output_field指定)
Count¶
班级Count(表达, 显著=假, 过滤器=无, **额外)[源代码]¶
返回通过提供的表达式关联的对象数。
默认别名:__count
返回类型:int
有一个可选的参数:
distinct¶
如果distinct=True,计数将只包含唯一实例。这是与COUNT(DISTINCT )…默认值是False.
Max¶
班级Max(表达, 输出字段=无, 过滤器=无, **额外)[源代码]¶
返回给定表达式的最大值。
默认别名:__max
返回类型:与输入字段相同,或output_field如果提供
Min¶
班级Min(表达, 输出字段=无, 过滤器=无, **额外)[源代码]¶
返回给定表达式的最小值。
默认别名:__min
返回类型:与输入字段相同,或output_field如果提供
StdDev¶
班级StdDev(表达, 样本=假, 过滤器=无, **额外)[源代码]¶
返回所提供表达式中数据的标准偏差
。
默认别名:__stddev
返回类型:float
有一个可选的参数:
sample¶
默认情况下,StdDev返回总体标准差。但是,如果sample=True,返回值为样本标准差。
SQLite
SQLite不提供StdDev从盒子里出来。实现可以作为SQLite的扩展模块使用。咨询SQLITE文档有关获取和安装此分机的说明。
Sum¶
班级Sum(表达, 输出字段=无, 过滤器=无, **额外)[源代码]¶
计算给定表达式的所有值的总和。
默认别名:__sum
返回类型:与输入字段相同,或output_field如果提供
Variance¶
班级Variance(表达, 样本=假, 过滤器=无, **额外)[源代码]¶
返回提供表达式中数据的方差
。
默认别名:__variance
返回类型:float
有一个可选的参数:
sample¶
默认情况下,Variance返回总体方差。但是,如果sample=True,返回值将是样本方差。
SQLite
SQLite不提供Variance从盒子里出来。实现可以作为SQLite的扩展模块使用。咨询SQLITE文档有关获取和安装此分机的说明。
Q()对象¶
班级Q[源代码]¶
A Q()对象,就像F对象,将SQL表达式封装在Python对象中,该对象可用于与数据库相关的操作。
总体而言,Q() objects使定义和重用条件成为可能。这允许复杂数据库查询的构造使用| (OR)和& (AND)运算符
,特别是在其他情况下不可能使用OR在……里面QuerySets.
Prefetch()对象¶
班级Prefetch(查找, queryset=无, to_attr=无)[源代码]¶
这个Prefetch()对象可以用来控制prefetch_related().
这个查找参数描述要遵循的关系,并与传递给的基于字符串的查找相同。prefetch_related()…例如:
>>> from django.db.models import Prefetch
>>> Question.objects.prefetch_related(Prefetch('choice_set')).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# This will only execute two queries regardless of the number of Question
# and Choice objects.
>>> Question.objects.prefetch_related(Prefetch('choice_set')).all()
<QuerySet [<Question: What's up?>]>
这个queryset论据提供了一个基础QuerySet用于给定的查找。这对于进一步筛选预取操作或调用select_related()因此,进一步减少了查询的数量:
>>> voted_choices = Choice.objects.filter(votes__gt=0)
>>> voted_choices
<QuerySet [<Choice: The sky>]>
>>> prefetch = Prefetch('choice_set', queryset=voted_choices)
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: The sky>]>
这个to_attr参数将预取操作的结果设置为自定义属性:
>>> prefetch = Prefetch('choice_set', queryset=voted_choices, to_attr='voted_choices')
>>> Question.objects.prefetch_related(prefetch).get().voted_choices
[<Choice: The sky>]
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
注解
使用时to_attr预取结果存储在列表中。与传统的速度相比,这可以提供一个显著的速度改进。prefetch_related调用,这些调用将缓存的结果存储在QuerySet举个例子。
prefetch_related_objects()¶
prefetch_related_objects(模型实例, *相关查找)[源代码]¶
预取模型实例可迭代上的给定查找。这在接收模型实例列表的代码中非常有用,而不是QuerySet例如,当从缓存中获取模型或手动实例化它们时。
传递模型实例的可迭代性(必须都属于同一类)和查找或Prefetch要预取的对象。例如:
>>> from django.db.models import prefetch_related_objects
>>> restaurants = fetch_top_restaurants_from_cache() # A list of Restaurants
>>> prefetch_related_objects(restaurants, 'pizzas__toppings')
FilteredRelation()对象¶
Django 2.0新版本:
班级FilteredRelation(关系名称, *, 条件=q())[源代码]¶
关系名称¶
要在其上筛选关系的字段的名称。
condition¶
A Q对象来控制筛选。
FilteredRelation与annotate()若要创建一个ON从句,当JOIN被执行。它不对默认关系起作用,而是对注释名称(pizzas_vegetarian在下面的例子中)。
例如,寻找有素食比萨饼的餐厅’mozzarella’以名义:
>>> from django.db.models import FilteredRelation, Q
>>> Restaurant.objects.annotate(
... pizzas_vegetarian=FilteredRelation(
... 'pizzas', condition=Q(pizzas__vegetarian=True),
... ),
... ).filter(pizzas_vegetarian__name__icontains='mozzarella')
如果有大量的比萨饼,则此查询集的性能优于:
>>> Restaurant.objects.filter(
... pizzas__vegetarian=True,
... pizzas__name__icontains='mozzarella',
... )
因为WHERE第一套的条款只适用于素食比萨。
FilteredRelation不支持:
跨越关系字段的条件。例如:
>>> Restaurant.objects.annotate(
... pizzas_with_toppings_startswith_n=FilteredRelation(
... 'pizzas__toppings',
... condition=Q(pizzas__toppings__name__startswith='n'),
... ),
... )
Traceback (most recent call last):
...
ValueError: FilteredRelation's condition doesn't support nested relations (got 'pizzas__toppings__name__startswith').
QuerySet.only()和prefetch_related().
A GenericForeignKey从父模型继承的。