在查询时发出了什么样(When QuerySets are evaluated)
QuerySet
可以被社团,过滤,切片,做为参数传递,这么些表现都不会对数据库举办操作。只要您询问的时候才真正的操作数据库。
下边的 QuerySet 行为会促成执行查询的操作:
循环(Iteration):QuerySet
是可迭代的,在您遍历对象时就会执行数据库操作。例如,打印出富有博文的大题目:
for e in Entry.objects.all():
print(e.headline)
切片(Slicing): QuerySet 是足以用 Python
的数组切片语法完成切片。一般的话对一个未查询的 QuerySet
切片就赶回另一个未查询的 QuerySet (新 QuerySet
不会被执行)。不过假使你在切除时使用了 “step” 参数,Django
仍会举行数据库操作并且重返列表对象。对一个询问过的QuerySet执行切片也会回来列表对象。
序列化/缓存化(Pickling/Caching): 详情请查看 pickling QuerySets。
这一节所强调的一点是询问结果是从数据库中读取的。
repr(). 调用 QuerySet 的 repr() 方法时,查询就会被周转。这对于
Python 命令行来说非凡便利,你可以采取 API 立时看到查询结果。
len(). 调用 QuerySet 的 len()方法,查询就会被周转。这正如您所料,会回到查询结果列表的长度。
小心:即使您想取得集合中著录的多寡,就无须采取 QuerySet 的 len()方法。因为平昔在数据库层面使用 SQL 的 SELECT COUNT(*)
会更加急速,Django 提供了 count() 方法就是这多少个缘故。详情参见下边的
count() 方法。
list(). 对 QuerySet 应用 list() 方法,就会运作查询。例如:
entry_list = list(Entry.objects.all())
要留心地是:使用那多少个方法会占用大量内存,因为 Django
将列表内容都载入到内存中。做为相比较,遍历 QuerySet
是从数据库读取数据,仅在利用某个对象时才将其载入到情节中。
Pickling QuerySets
倘若您要 序列化(pickle) 一个 QuerySet,Django
首先就会将查询对象载入到内存中以形成连串化,这样您就足以第一时间使用对象(直接从数据库中读取数据需要肯定时间,这正是缓存所想制止的)。而系列化是缓存化的先行工作,所以在缓存查询时,首先就会展开体系化工作。这代表当您反连串化
QuerySet 时,第一时间就会从内存中获得查询的结果,而不是从数据库中搜寻。
假如您只是想系列化部分必要的音信以便晚些时候可以从数据库中重建 Queryset
,这只系列化 QuerySet 的 query
属性即可。接下来您就足以选拔上边的代码重建原来的 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(QuerySet API)
filter(**kwargs)
归来一个新的 QuerySet ,它蕴含了与所给的筛选标准相匹配的靶子。
这些筛选标准(**kwargs)在上边的字段筛选(菲尔德(Field) lookups)
中有详尽介绍。五个标准之间在 SQL 语句中是 AND 关系。
exclude(**kwargs)
回到一个新的 QuerySet,它包含这多少个与所给筛选标准不兼容的靶子。
这个筛选标准(**kwargs)也在底下的 字段筛选(菲尔德(Field)(Field) lookups)
中有详细描述。三个条件之间在 SQL 语句中也是 AND 关系,然则总体又是一个
NOT() 关系。
下边的例子剔除了出版日期 pub_date 晚于 2005-1-3 并且大标题 headline 是
“Hello” 的装有博文(entry):
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'
OR NOT headline = 'Hello'
要小心第二个例子是有诸多限制的。
annotate(*args, **kwargs)
我们可以为 QuerySet
中的每个对象添加声明。可以经过总结查询结果中各种对象所涉嫌的对象集合,从而得出统计值(也得以是平均值或总和,等等),做为
QuerySet 中目标的诠释。annotate() 中的每个参数都会被做为表明添加到
QuerySet 中回到的对象。
Django 提供的诠释函式在底下的 (注明函式Aggregation Functions)
有详尽介绍。
诠释会采纳重要字参数来做为表明的别名。其中任何参数都会变卦一个别名,它与阐明函式的称号和被诠释的
model 相关。
譬如说,你正在操作一个博客列表,你想明白一个博客究竟有多少篇博文:
>>> 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 model 类本身并没有概念 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(*fields)
默认处境下, QuerySet 再次回到的询问结果是按照 model 类的 Meta 设置所提供的
ordering 项中定义的排序元组来举行对象排序的。你可以利用 order_by
方法覆盖此前 QuerySet 中的排序设置。
例如:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
回到结果就会先依照 pub_date 举行升序排序,再按照 headline
举行降序排序。 “-pub_date”
后边的负号”-“表示降序排序。默认是行使升序排序。要自由排序,就使用
“?”,例如:
Entry.objects.order_by('?')
注意:order_by(‘?’)
可能会要命缓慢和消耗过多资源,这取决于你所使用的数据库。
要基于另外 model
字段排序,所用语法和跨关系查询的语法相同。就是说,用五个连续的下划线(__)连接关联
model 和 要排序的字段名称, 而且可以一贯延伸。例如:
Entry.objects.order_by('blog__name', 'headline')
只要你想对涉及字段排序,在未曾点名 Meta.ordering 的情况下,Django
会采纳默认排序设置,就是服从关联 model 的主键举办排序。例如:
Entry.objects.order_by('blog')
等价于:
Entry.objects.order_by('blog__id')
这是因为 Blog model 没有注解排序项的原委。
Django 1.7新添加:
# No Join
Entry.objects.order_by('blog_id') #可以避免JOIN的代价
# Join
Entry.objects.order_by('blog__id')
尽管您利用了 distinct() 方法,那么在对关系字段排序时要非凡小心谨慎。
在 Django 当中是足以依照多值字段(例如 ManyToMany
字段)举办排序的。但是,这么些特性虽然先进,不过并不实用。除非是你早已很清楚过滤结果或可用数据中的每个对象,都只有一个相关联的靶兔时(就是一定于只是一对一关乎时),排序才会适合您预期的结果,所以对多值字段排序时要卓殊注意。
假诺您不想对任何字段排序,也不想行使 model
中原本的排序设置,那么可以调用无参数的 order_by() 方法。
对于排序项是不是合宜大小写敏感,Django
并从未提供设置模式,这点一滴在于后端的数据库对排序大小写什么处理。
您可以令某个查询结果是可排序的,也得以是不行排序的,这取决于
QuerySet.ordered 属性。若是它的值是 True ,那么 QuerySet 就是可排序的。
reverse()
使用 reverse() 方法会对查询结果开展反向排序。调用三次 reverse()方法相当于排序没发出改过。
要得到查询结果中最后六个目标,可以如此写:
my_queryset.reverse()[:5]
要小心这种措施与 Python
语法中的从尾部切片是一点一滴不一样的。在上头的例子中,是先拿走终极一个元素,然后是倒数第二个,依次拍卖。但是如果我们有一个
Python 队列,使用 seq[-5:]时,却是先拿到倒数第六个要素。Django
之所以采纳 reverse 来收获倒数的记录,而不匡助切片的方法,原因就是后人在
SQL 中难以做好。
再有一些要留意,就是 reverse() 方法应该只遵从于已定义了排序项 QuerySet
(例如,在询问时行使了order_by()方法,或是在 model
类当中直接定义了排序项). 如若并从未明确概念排序项,那么调用 QuerySet,
calling reverse() 就没怎么实际意义(因为在调用 reverse()在此以前,数据尚未概念排序,所以在那事后也不会开展排序。)
distinct()
回到一个新的 QuerySet ,它会在执行 SQL 查询时利用 SELECT
DISTINCT。这表示重回结果中的重复记录将被去除。
默认情状下, QuerySet
并会去除重复的笔录。在实质上当中,这不是何许问题,因为象
Blog.objects.all() 这样的询问并不会生出重复的笔录。不过,如果你使用
QuerySet 做多表查询时,就很可能会爆发重复记录。那时,就可以使用
distinct() 方法。
Note
在 order_by(*fields) 中出现的字段也会蕴藏在 SQL SELECT 列中。假设和
distinct()同时选拔,有时回来的结果却与预期的例外。这是因为:假诺您对跨关系的关联字段展开排序,那一个字段就会被添加到被挑选的列中,那就可能爆发重复数据(比如,其他的列数据都如出一辙,只是提到字段的值不同)。但由于
order_by
中的关联字段并不会产出在回来结果中(他们单独是用来促成order),所以有时回来的数据看上去就象是并没有展开过
distinct 处理一样。
平等的来由,假诺您用 values() 方法赢得被拔取的列,就会意识带有在
order_by() (或是 model 类的 Meta
中设置的排序项)中的字段也包含在中间,就会对回到的结果爆发潜移默化。
这章节强调的就是在您接纳 distinct()时,要小心翼翼对待关联字段排序。同样的,在同时选用 distinct() 和 values()时,假诺排序字段并从未出现在 values() 再次回到的结果中,那么也要引起注意。
values(*fields)
归来一个 ValuesQuerySet —-一个新鲜的 QuerySet
,运行后得到的并不是一多样 model
的实例化对象,而是一个可迭代的字典序列。
每个字典都表示一个目的,而键名就是 model 对象的特性名称。
下边的例证就对 values() 拿到的字典与价值观的 model 对象开展了相比:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
[<Blog: Beatles Blog>]
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]
values() 可以收到可选的职位参数,*fields,就是字段的称号,用来界定
SELECT 拔取的数目。假诺你指定了字段参数,每个字典就会以 Key-Value
的款式保留你所指定的字段信息;假诺没有点名,每个字典就会含有当前数量表当中的所有字段音信。
例如:
>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]
下面这多少个细节值得注意:
假若你有一个名为 foo 的ForeignKey 字段,默认状况下调用 values()重回的字典中含有键名为 foo_id 的字典项,因为它是一个分包的 model
字段,用来保存关联对象的主键值( foo 属性用来维系相关联的 model
)。当您利用 values() 并传递字段名称时, 传递foo 或 foo_id
都会得到一致的结果 (字典中的键名会自动换成你传递的字段名称)。
例如:
>>> Entry.objects.values()
[{'blog_id': 1, 'headline': u'First Entry', ...}, ...]
>>> Entry.objects.values('blog')
[{'blog': 1}, ...]
>>> Entry.objects.values('blog_id')
[{'blog_id': 1}, ...]
在 values() 和 distinct()同时采用时,要注意排序项会影响重返的结果,详情请查看下边 distinct()一节。
在values()之后采用defer()和only()是杯水车薪的。
ValuesQuerySet
是特别实惠的。利用它,你就足以只收获你所需的这部分数量,而无需同时读取其他的无用数据。
最终,要唤醒的是,ValuesQuerySet 是 QuerySet 的一个子类,所以它装有
QuerySet 所有的法子。你可以对它调用 filter() 或是 order_by()以及其他措施。所以下边俩种写法是等价的:
Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()
Django 的编辑们更爱好第三种写法,就是先写影响 SQL
的不二法门,再写影响输出的模式(比如例中先写 order,再写values
),但这一个都无足轻重,完全视你个人喜好而定。
也可以针对一对一、多对多、外键关系对象的域:
Blog.objects.values('name', 'entry__headline')
[{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]
当指向多对多涉及时,因为关乎对象可能有好多,所以同一个目的会基于不同的多对多涉及再次回到多次。
values_list(*fields)
它与 values() 至极相像,只然而后者再次回到的结果是字典连串,而 values()重回的结果是元组体系。每个元组都富含传递给 values_list()的字段名称和内容。比如第一项就对应着第一个字段,例如:
>>> Entry.objects.values_list('id', 'headline')
[(1, u'First entry'), ...]
倘使你传递了一个字段做为参数,那么您能够行使 flat 参数。虽然它的值是
True,就代表再次回到结果都是独立的值,而不是元组。下边的事例会讲得更领会:
>>> Entry.objects.values_list('id').order_by('id')
[(1,), (2,), (3,), ...]
>>> Entry.objects.values_list('id', flat=True).order_by('id')
[1, 2, 3, ...]
倘使传递的字段不止一个,使用 flat 就会促成错误。
万一你没给 values_list() 传递参数,它就会听从字段在 model
类中定义的逐条重返所有的字段。
留意这么些法子再次回到的是 ValuesListQuerySet对象,和列表相似但并不是列表,需要列表操作时需list()转为列表。
dates(field, kind, order=’ASC’)
回去一个 DateQuerySet ,就是领取 QuerySet
查询中所包含的日子,将其重组一个新的 datetime.date 对象的列表。
field 是您的 model 中的 Date菲尔德(Field)(Field) 字段名称。
kind 是 “year”, “month” 或 “day” 之一。 每个
datetime.date对象都会基于所给的 type 举行截减。
“year” 重回所有时间值中非重复的年分列表。
“month” 再次来到所有时间值中非重复的年/月列表。
“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', '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)]
datetimes(field, kind, order=’ASC’)
回去一个 Date提姆(Tim)eQuerySet ,就是提取 QuerySet
查询中所包含的日子,将其构成一个新的 datetime.datetime 对象的列表。
none()
回去一个 EmptyQuerySet — 它是一个运转时只回去空列表的
QuerySet。它时时用在这种场面:你要回来一个空列表,然则调用者却需要接受一个
QuerySet 对象。(这时,就足以用它代表空列表)
例如:
>>> Entry.objects.none()
[]
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True
all()
归来当前 QuerySet (或者是传递的 QuerySet 子类)的一分拷贝。
这在一些场地是很用的,比如,你想对一个 model manager 或是一个 QuerySet
的查询结果做越来越的过滤。你就足以调用 all()拿到一分拷贝以继续操作,从而确保原 QuerySet 的安全。
当一个QuerySet查询后,它会缓存查询结果。假诺数据库爆发了变更,就足以调用all()来更新查询过的QuerySet。
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().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.db import models
class City(models.Model):
# ...
pass
class Person(models.Model):
# ...
hometown = models.ForeignKey(City)
class Book(models.Model):
# ...
author = models.ForeignKey(Person)
接下来调用 Book.objects.select_related().get(id=4) 将缓存关联的 Person
和 City:
b = Book.objects.select_related('person__city').get(id=4)
p = b.author # Doesn't hit the database.
c = p.hometown # Doesn't hit the database.
b = Book.objects.get(id=4) # No select_related() in this example.
p = b.author # Hits the database.
c = p.hometown # Hits the database.
prefetch_related()
对此多对多字段(ManyToManyField)和有些多字段,可以利用prefetch_related()来拓展优化。或许你会说,没有一个叫OneToMany菲尔德(Field)(Field)的东西啊。实际上
,ForeignKey就是一个多对一的字段,而被ForeignKey关联的字段就是一对多字段了。
prefetch_related()和select_related()的计划性目标很相似,都是为了缩短SQL查询的数目,可是贯彻的方法不相同。后者是经过JOIN语句,在SQL查询内解决问题。可是对于多对多涉及,使用SQL语句解决就显得有点不太明智,因为JOIN得到的表将会很长,会导致SQL语句运行时刻的扩充和内存占用的扩充。若有n个对象,每个对象的多对多字段对应Mi条,就会生成Σ(n)Mi
行的结果表。
prefetch_related()的缓解措施是,分别查询每个表,然后用Python处理他们中间的涉及。
例如:
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): # __unicode__ on Python 2
return "%s (%s)" % (self.name, ", ".join([topping.name
for topping in self.toppings.all()]))
运行
>>> Pizza.objects.all().prefetch_related('toppings')
能够联手查询:
class Restaurant(models.Model):
pizzas = models.ManyToMany(Pizza, related_name='restaurants')
best_pizza = models.ForeignKey(Pizza, related_name='championed_by')
下面的事例都得以
>>> Restaurant.objects.prefetch_related('pizzas__toppings')
>>> Restaurant.objects.prefetch_related('best_pizza__toppings')
>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')
extra(select=None, where=None, params=None, tables=None,
order_by=None, select_params=None)
稍许境况下,Django 的查询语法难以简练地发挥复杂的 WHERE
子句。对于这种状态,Django 提供了 extra() QuerySet
修改机制,它能在QuerySet 生成的 SQL 从句中注入新子句。
由于产品差异的原委,这个自定义的询问难以维持在不同的数据库之间包容(因为你手写
SQL 代码的缘由),而且违背了 DRY 原则,所以如非必要,如故尽量避免写
extra。
在 extra 可以指定一个或三个 params 参数,如 select,where 或
tables。所有参数都是可选的,但您足足要利用一个。
select
select 参数可以让你在 SELECT
从句中添加另外字段音讯。它应当是一个字典,存放着属性名到 SQL
从句的炫耀。
例如:
Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
结果中每个 Entry 对象都有一个卓绝的 is_recent
属性,它是一个布尔值,表示 pub_date 是否晚于二零零六年四月1号。
Django 会直接在 SELECT 中参预相应的 SQL 片断,所以转换后的 SQL 如下:
SELECT blog_entry.*, (pub_date > '2006-01-01')
FROM blog_entry;
下面这一个事例更复杂一些;它会在每个 Blog 对象中添加一个 entry_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=…) 中的 SQL
语句传递参数,这时就可以运用 select_params 参数。因为 select_params
是一个行列,而 select
属性是一个字典,所以两岸在配合时应正确地一一对应。在这种情形下中,你应该运用
django.utils.datastructures.SortedDict 匹配 select
的值,而不是采纳相似的 Python 队列。
例如:
Blog.objects.extra(
select=SortedDict([('a', '%s'), ('b', '%s')]),
select_params=('one', 'two'))
在选拔 extra() 时要避免在 select 字串含有 “%%s” 子串, 这是因为在 Django
中,处理 select 字串时追寻的是 %s 而并非转义后的 % 字符。所以一旦对 %
举行了转义,反而得不到科学的结果。
where / tables
你可以动用 where 参数显示定义 SQL 中的 WHERE
从句,有时也足以运行非显式地连续。你仍可以应用 tables 手动地给 SQL FROM
从句添加此外表。
where 和 tables 都接受字符串列表做为参数。所有的 where 参数相互之间都是
“AND” 关系。
例如:
Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])
大致可以翻译为如下的 SQL:
SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);
在行使 tables
时,假诺您指定的表在查询中已出现过,那么要那么些小心。当您通过 tables
参数添加此外数据表时,假使这么些表已经被含有在询问中,那么 Django
就会以为你想再一回包含那一个表。这就造成了一个题材:由于重复出现反复的表会被给予一个别名,所以除了第一次之外,每个重复的表名都会独家由
Django 分配一个别名。所以,尽管你而且拔取了 where
参数,在其中使用了某个重复表,却不知它的别名,那么就会导致错误。
貌似景观下,你只会添加一个未在查询中出现的新表。但是要是上边所涉嫌的特有情状时有爆发了,那么能够运用如下措施缓解。首先,判断是否有必不可少要出新重复的表,能否将再次的表去掉。假使这一点无效,就试着把
extra()调用放在查询结构的起首处,因为第一次出现的表名不会被重命名,所以可能能迎刃而解问题。假使这也特别,这就翻开生成的
SQL 语句,从中找出各个数据库的别名,然后依此重写 where
参数,因为假诺你每一次都用同样的法子调用查询(queryset),表的别名都不会暴发变化。所以你可以向来使用表的别名来布局
where。
order_by
假诺您已由此 extra()添加了新字段或是数据库,此时若想对新字段举办排序,就足以给 extra() 中的
order_by 参数传递一个排序字符串体系。字符串可以是 model
原生的字段名(与行使普通的 order_by() 方法一致),也得以是
table_name.column_name 这种情势,或者是您在 extra() 的 select
中所定义的字段。
例如:
q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
q = q.extra(order_by = ['-is_recent'])
这段代码按照 is_recent 对记录进行排序,字段值是 True 的排在后边,False
的排在前面。(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'])
defer(*fields)
在某些数据复杂的环境下,你的 model
可能带有非凡多的字段,可能某些字段包含非凡多的数量(比如,文档字段),或者将其转化为
Python
对象会消耗分外多的资源。在这种景色下,有时你也许并不需要那种字段的音讯,那么您可以让
Django 不读取它们的多少。
将不想载入的字段的名称传给 defer() 方法,就足以成功延后载入:
Entry.objects.defer("lede", "body")
延后截入字段的询问再次回到的仍是 model
类的实例。在你拜访延后载入字段时,你还是可以博得字段的情节,所例外的是,内容是在你拜访延后字段时才读取数据库的,而日常字段是在运转查询(queryset)时就四遍性从数据库中读取数据的。
你能够屡屡调用 defer() 方法。每个调用都得以添加新的延后载入字段:
# Defers both the body and lede fields.
Entry.objects.defer("body").filter(headline="Lennon").defer("lede")
对延后载入字段举办排序是不会起效果的;重复添加延后载入字段也不会有何不良影响。
您也得以延后载入关联 model 中的字段(前提是你拔取 select_related()载入了关联 model),用法也是用双下划线连接关联字段:
Blog.objects.select_related().defer("entry__lede", "entry__body")
万一您想解除延后载入的设置,只要采纳将 None 做为参数传给 defer() 即可:
# Load all fields immediately.
my_queryset.defer(None)
稍许字段无论你怎么指定,都不会被延后加载。比如,你永远不可能延后加载主键字段。假若您利用
select_related() 得到关联 model 字段音讯,那么您就不可能延后载入关联
model 的主键。(假设如此做了,尽管不会抛出错误,事实上却不完了延后加载)
Note
defer() 方法(和随之提到的 only() 方法)
都只适用于特定情景下的高等级属性。它们可以提供性能上的优化,可是前提是您早就对您用到的查询有过很深刻细致的分析,相当明白你需要的到底是怎么新闻,而且已经对你所需要的数码和默认意况下回到的具有数据进行比对,清楚两者之间的异样。那形成了上述工作之后,再拔取这两种艺术举行优化才是有意义的。所以当您刚起初构建你的采取时,先不用急着使用
defer()方法,等你曾经写完询问并且分析成哪些方面是热门应用以后,再用也不迟。
only(*fields)
only() 方法或多或少与 defer()的效益反倒。如若您在提取数据时愿意某个字段不应该被延后载入,而应该立刻载入,那么您就足以做使用
only() 方法。如若你一个 model
,你希望它具有的字段都延后加载,唯有某多少个字段是即时载入的,那么你就应有运用
only() 方法。
假若您有一个 model,它有 name, age 和 biography
三个字段,那么下边二种写法效果同样的:
Person.objects.defer("age", "biography")
Person.objects.only("name")
您随便啥时候调用
only(),它都会登时改变载入设置。这与它的命名相当吻合:唯有 only
中的字段会及时载入,而此外的则都是延后载入的。由此,连续调用 only()时,唯有最后一个 only 方法才会生效:
# This will defer all fields except the headline.
Entry.objects.only("body", "lede").only("headline")
是因为 defer() 可以递增(每一次都添加字段到延后载入的列表中),所以您可以将
only() 和 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")
using(alias)
使用多少个数据库时利用,参数是数据库的alias
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')
select_for_update(nowait=False)
回去queryset,并将急需革新的行锁定,类似于SELECT … FOR UPDATE的操作。
entries = Entry.objects.select_for_update().filter(author=request.user)
抱有匹配的entries都会被锁定直到此次业务停止。
raw(raw_query, params=None, translations=None)
执行raw SQL queries
不回来查询的办法(QuerySet methods that do not return QuerySets)
下边所列的 QuerySet 方法效果于 QuerySet,却并不回去 other than a
QuerySet。
这多少个办法并不行使缓存(请查看 缓存与查询(Caching and
QuerySets))。所以它们在运作时是当时读取数据库的。
get(**kwargs)
回去与所给的筛选标准相匹配的对象,筛选标准在 字段筛选标准(Field(Field) lookups)
一节中有详尽介绍。
在动用 get() 时,假诺符合筛选标准的目的领先一个,就会抛出
MultipleObjectsReturned 非常。MultipleObjectsReturned 是 model
类的一个特性。
在接纳 get() 时,假诺没有找到符合筛选标准的目的,就会抛出 DoesNotExist
非常。这个卓殊也是 model 对象的一个属性。例如:
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.")
create(**kwargs)
创制对象并还要保留对象的立刻方法:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
和
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
是千篇一律的。
force_insert 参数在别处有详实介绍,它代表把当下 model
当成一个新目标来创立。一般情形下,你不用担心这点,可是尽管您的 model
的主键是您手动指定的,而且它的值已经在数据库中存在,那么调用 create()就会破产,并抛出
IntegrityError。这是因为主键值必须是唯一的。所以当您手动指定主键时,记得要抓好处理相当的预备。
get_or_create(defaults=None,**kwargs)
这是一个便利实际应用的点子,它遵照所给的筛选标准查询对象,假若目的不设有就创立一个新对象。
它回到的是一个 (object, created) 元组,其中的 object
是所读取或是创立的靶子,而 created 则是一个布尔值,它象征后边提到的
object 是否是新成立的。
这代表它能够使得地减小代码,并且对编写数据导入脚本非凡实用。例如:
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()
地点的代码会趁机 model 中字段数量的骤增而变得越来越庸肿。接下来用
get_or_create() 重写:
obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
defaults={'birthday': date(1940, 10, 9)})
在这边要留意 defaults
是一个字典,它仅适用于创造对象时为字段赋值,而并不适用于查找已存在的对象。
get_or_create() 所收受的紧要字参数都会在调用 get()时被应用,有一个参数例外,就是 defaults。在动用get_or_create()时只要找到了目的,就会回来这些目标和
False。尽管没有找到,就会实例化一个新目的,并将其保存;同时再次来到这些新对象和
True。创造新对象的步调大致如下:
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
params.update(defaults)
obj = self.model(**params)
obj.save()
用自然语言描述:从非 ‘defaults’
关键字参数中排除含有双下划线的参数(因为双下写道表示非精确查询),然后再添加
defaults 字典的始末,即使键名与已部分重大字参数重复,就以 defaults
中的内容为准, 然后将整治后的重要字参数传递给 model
类。当然,这只是算法的简化描述,实际上对众多细节尚未提及,比如对充足和边界条件的拍卖。假如你对此感兴趣,不妨看一下原代码。
比方你的 model 恰巧有一个字段,名称正是 defaults,而且你想在
get_or_create() 中用它做为精确查询的原则, 就得使用 ‘defaults__exact’
(此前提过 defaults 只好在创立时对目的赋值,而不可能开展询问),象下边这样:
Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
设若您手动指定了主键,那么使用 get_or_create() 方法时也会象 create()一样,抛出像样的不行。当你手动指定了主键,若主键值已经在数据库中设有,就会抛出一个
IntegrityError 非常。
最后提一下在 Django 视图(views)中使用 get_or_create()时要小心的一些。如上所说,对于在本子中剖析数据和添加新数据而言,get_or_create()是非凡实惠的。不过要是你是在视图中接纳 get_or_create(),那么就要特别留意,要确认是在 POST
请求中运用,除非你有很必要和很丰裕的说辞才不这么做。而在 GET
请求中动用的话,不会对数据发生任何意义。而采纳 POST
的话,每个发往页面的伏乞都会对数据有肯定的副成效。
Note
由此多对多关系拔取时要注意:
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 = 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
不和book相关联的Chapter就不会被查找到了。
update_or_create(defaults=None, **kwargs)
与地点类似
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
for key, value in updated_values.iteritems():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
updated_values.update({'first_name': 'John', 'last_name': 'Lennon'})
obj = Person(**updated_values)
obj.save()
可以简写为:
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon', defaults=updated_values)
bulk_create(objs, batch_size=None)
批量创建
>>> Entry.objects.bulk_create([
... Entry(headline="Django 1.0 Released"),
... Entry(headline="Django 1.1 Announced"),
... Entry(headline="Breaking: Django is awesome")
... ])
优于:
Entry.objects.create(headline="Python 1.0 Released")
Entry.objects.create(headline="Python 1.1 Planned")
count()
归来数据库中优异查询(QuerySet)的靶子数量。 count() 不会抛出另外非常。
例如:
# 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()
count() 会在后端执行 SELECT COUNT(*) 操作,所以你应当尽可能利用 count()而不是对回到的询问结果使用 len() 。
依照你所拔取的数据库(例如 PostgreSQL 和 MySQL),count()可能会回去长整型,而不是普普通通的 Python
整数。这真的是一个很奇怪的举动,没有怎么实际意义。
in_bulk(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([])
{}
假定你给 in_bulk() 传递的是一个空列注明,拿到就是一个空字典。
iterator()
运行查询(QuerySet),然后遵照结果再次来到一个 迭代器(iterator。
做为相比较,使用 QuerySet
时,从数据库中读取所有记录后,四回性将具备记录实例化为对应的靶子;而
iterator()则是读取记录后,是分多次对数码实例化,用到哪个目的才实例化哪个目标。相对于三遍性再次回到很多对象的
QuerySet,使用迭代器不仅效用更高,而且更省去内存。
要专注的是,假诺将 iterator() 效用于
QuerySet,这就象征会再两遍运行查询,就是说会运行一次查询。
latest(field_name=None)
据悉时间字段 field_name 得到最新的靶子。
下边这些例子遵照 pub_date 字段得到数据表中流行的 Entry 对象:
Entry.objects.latest('pub_date')
借使你在 model 中 Meta 定义了 get_latest_by 项, 那么你能够略去
field_name 参数。Django 会将 get_latest_by 做为默认设置。
和 get(), latest() 一样,倘使遵照所给条件尚未找到匹配的靶子,就会抛出
DoesNotExist 相当。
留神 latest()和earliest() 是纯粹为了易用易读而留存的法子。
earliest(field_name=None)
类似于latest()
first()
p = Article.objects.order_by('title', 'pub_date').first()
相当于:
try:
p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
p = None
last()
类似于first()
aggregate(*args, **kwargs)
因而对 QuerySet 举办总计,返回一个聚合值的字典。 aggregate()中每个参数都指定一个带有在字典中的重返值。
聚集使用紧要字参数做为注脚的称谓。每个参数都有一个为其订做的名称,这些称谓取决于聚合函式的函数名和聚合字段的名目。
诸如,你正在处理博文,你想清楚博客中一起有些许篇博文:
>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}
通过在 aggregate 指定关键字参数,你可以控制再次回到的联谊名称:
>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}
exists()
一经 QuerySet 包含有多少,就回到 True 否则就重临False。这说不定是最快最简便的查询办法了.
update()
更新
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')
delete()
删除
>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
字段筛选标准(菲尔德(Field) lookups)
字段筛选标准决定了你怎么样社团 SQL 语句中的 WHERE 从句。它们被指定为
QuerySet 中 filter(),exclude() 和 get() 方法的要害字参数。
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;
iexact
忽略大小写的匹配。
例如:
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;
SQLite 用户要留意
在采纳 SQLite 作为数据库,并且选用 Unicode (non-ASCII)
字符串时,请先查看 database note 中有关字符串比对那一节内容。SQLite 对
Unicode 字符串,不能做忽略大小写的分外。
contains
大小写敏感的隐含匹配。
例如:
Entry.objects.get(headline__contains='Lennon')
等价于 SQL :
SELECT ... WHERE headline LIKE '%Lennon%';
要注意,上述语句将配合大题目 ‘Today Lennon honored’ ,但不可以匹配 ‘today
lennon honored’。
SQLite 不帮助大小写敏感的 LIKE 语句;所以对 SQLite 使用 contains
时就和接纳 icontains 一样。
icontains
大意大小写的盈盈匹配。
例如:
Entry.objects.get(headline__icontains='Lennon')
等价于 SQL:
SELECT ... WHERE headline ILIKE '%Lennon%';
SQLite 用户请留心
运用 SQLite 数据库并运用 Unicode (non-ASCII) 字符串时,请先查看 database
note 文档中有关字符串比对那一节内容。
in
是否在一个加以的列表中。
例如:
Entry.objects.filter(id__in=[1, 3, 4])
等价于 SQL:
SELECT ... WHERE id IN (1, 3, 4);
您也可以把询问(queryset)结果作为动态的列表,从而代替固定的列表:
inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)
做动态列表的 queryset 运行时就会被做为一个子询问:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
倘使您传递了一个 ValuesQuerySet 或 ValuesListQuerySet
(它们是调用查询集上 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)
warning
query
属性本是一个不明白的内部属性,即便她在地点的代码中劳作得很好,不过它的API很可能会在不同的
Django 版本中平日改变。
性能考虑
要谨小慎微采用嵌套查询,并且要对您所采取的数据库性能有所明白(如若不打听,就去做一下性能测试)。有些数据库,比如知名的MySQL,就不可以很好地优化嵌套查询。所以在下面的案例中,先在首先个查询中提取值列表,然后再将其传递给第二个查询,会对性能有较高的晋级。说白了,就是用多个高速的查询替换掉一个失效的询问:
values = Blog.objects.filter(
name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))
gt
大于。
gte
不止等于。
lt
小于。
lte
紧跟于等于。
startswith
大大小小写敏感的以….起头。
istartswith
大意大小写的以….最先。
endswith
大大小小写敏感的以….结尾。
iendswith
不经意大小写的以….结尾。
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 当成 SQL 中的 BETWEEN 来用,比如日期,数字,甚至是字符。
year
对日期/时间字段精确匹配年分,年分用四位数字代表。
例如:
Entry.objects.filter(pub_date__year=2005)
等价于 SQL:
SELECT ... WHERE EXTRACT('year' FROM pub_date) = '2005';
(不同的数据库引擎中,翻译得到的 SQL 也不尽相同。)
month
对日期/时间字段精确匹配月分,用整数表示月分,比如 1 表示十一月,12
表示十四月。
day
对日期/时间字段精确匹配日期。
要注意的是,这个匹配只会博得所有 pub_date 字段内容是代表 某月的第三天
的记录,如二月三号,一月三号。而三月二十三号就不在此列。
week_day
对日期/时间字段匹配星期几
例如:
Entry.objects.filter(pub_date__week_day=2)
等价于 SQL:
SELECT ... WHERE EXTRACT('dow' FROM pub_date) = '2';
(不同的数据库引擎中,翻译得到的 SQL 也不尽相同。)
要留意的是,那段代码将得到 pub_date 字段是周天的享有记录
(西方习惯于将周一看做一周的第二天),与它的刻钟信息无关。星期以礼拜五做为第一天,以周一做为最终一天。
hour
minute
second
isnull
按照 SQL 查询是空 IS NULL 仍旧非空 IS NOT NULL,重返相应的 True 或
False。
例如:
Entry.objects.filter(pub_date__isnull=True)
等价于 SQL:
SELECT ... WHERE pub_date IS NULL;
search
使用全文索引做全文检索。它与 contains
相似,但利用全文索引做搜索会更快一些。
例如:
Entry.objects.filter(headline__search="+Django -jazz Python")
等价于:
SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);
要注意那么些主意仅适用于 MySQL ,并且要求安装全文索引。默认情形下 Django
使用 BOOLEAN MODE 形式。详见 Please check MySQL documentation for
additional details.
regex
大小写敏感的正则表明式匹配。
它要求数据库帮助正则表明式语法,而 SQLite 却从不内建正则表明式协助,因此SQLite 的这些特性是由一个名为 REGEXP 的 Python 方法实现的,所以要用到
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
不经意大小写的正则表明式匹配。
聚合函式(Aggregation Functions)
Avg
回来所给字段的平均值。
默认别名:<field>__avg
回到类型: float
Count
遵照所给的涉及字段再次来到被关联 model 的数量。
默认别名: <field>__count
回到类型: int
它有一个可选参数:
distinct
设若 distinct=True,那么只回去不另行的实例数量,相当于 SQL 中的
COUNT(DISTINCT field)。默认值是 False。
Max
默认别名: <field>__max
回来类型: 与所给字段值相同
Min
回到所给字段的很小值。
默认别名: <field>__min
回来类型: 与所给字段相同
StdDev
回到所给字段值的标准差。
默认别名: <field>__stddev
回来类型: float
它有一个可选参数:
sample
默认情形下, StdDev 重临一个完整偏差值,但是如果sample=True,则赶回一个样本偏差值。
SQLite
SQLite 本身并不提供 StdDev 帮助,可以运用 SQLite
的外置模块实现这么些功能。详情请查六柱预测应的 SQLite
文档,驾驭怎么样取得和安装增加。
Sum
总计所给字段值的总和
默认别名: <field>__sum
归来类型: 与所给字段相同
Variance
回来所给字段值的正规方差。
默认别名: <field>__variance
归来类型: float
它有一个可选参数:
sample
默认情状下, Variance 再次回到的是完整方差;即便sample=True,重返的则是样式方差。