何时对查询集求值
本质上,可以创建、过滤、切片和传递查询集而不用真实操作数据库。在你对查询集做求值之前,不会发生任何实际的数据库操作。
你可以使用下列方法对查询集求值:
-
迭代。queryset是可迭代的,它在首次迭代查询集时执行实际的数据库查询。例如, 下面的语句会将数据库中所有Entry 的headline 打印出来:
for e in Entry.objects.all(): print(e.headline)
注意:不要使用上面的语句来验证在数据库中是否至少存在一条记录。使用 exists()方法更高效。
-
切片。一个未求值的查询集进行切片通常返回另一个未求值的QuerySet,但是如果你使用切片的”step“参数,Django 将执行数据库查询并返回一个列表。对一个已经求值的查询集进行切片将返回一个列表。还要注意,虽然对未求值的查询集进行切片返回另一个未求值的查询集,但是却不不可以进一步修改它了(例如,添加更多的Filter,或者修改排序的方式),因为这将不太好翻译成SQL而且含义也不清晰。
-
序列化/缓存。 序列化查询集的细节参见下面一节。本节提到它的目的是强调序列化将读取数据库
-
repr()。 当对查询集调用repr() 时,将对它求值。这是为了在Python 交互式解释器中使用的方便,这样你可以在交互式使用这个API 时立即看到结果。
-
len()。 当你对查询集调用len() 时, 将对它求值。正如你期望的那样,返回一个查询结果集的长度。
-
list()。 对查询集调用list() 将强制对它求值。例如:
entry_list = list(Entry.objects.all())
-
bool()。 测试一个查询集的布尔值,例如使用bool()、or、and 或者if 语句将导致查询集的执行。如果至少有一个记录,则查询集为True,否则为False。例如:
if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")
注:如果你需要知道是否存在至少一条记录(而不需要真实的对象),使用 exists() 将更加高效。
Pikle 查询集
如果你Pickle一个查询集,它将在Pickle 之前强制将所有的结果加载到内存中。Pickle 通常用于缓存之前,并且当缓存的查询集重新加载时,你希望结果已经存在随时准备使用(从数据库读取耗费时间,就失去了缓存的目的)。这意味着当你Unpickle查询集时,它包含Pickle 时的结果,而不是当前数据库中的结果。
如果此后你只想Pickle 必要的信息来从数据库重新创建查询集,可以Pickle查询集的query 属性。然后你可以使用类似下面的代码重新创建原始的查询集(不用加载任何结果):
>>> 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。然而,这里讲到的Pickle 和Unpickle 这个属性的内容是安全的(和完全支持的)。
不可以在不同版本之间共享Pickle 的结果
查询集 API
下面是对于查询集的正式定义:
class QuerySet([model=None, query=None, using=None])[source]¶
通常你在使用QuerySet时会以链式的filter 来使用。为了让这个能工作,大部分QuerySet 方法返回新的 QuerySet。这些方法在本节将详细讲述。
QuerySet 类具有两个公有属性用于内省:
如果QuerySet 是排好序的则为True —— 例如有一个order_by() 子句或者模型有默认的排序。否则为False .
如果现在执行,则返回将使用的数据库。
返回新的查询集 的方法
annotate
annotate(*args, **kwargs)
使用提供的查询表达式Annotate 查询集中的每个对象。查询表达式可以是一个简单的值、模型(或关联模型)字段的一个引用或对查询集中的对象一个聚合函数(平均值、和等)。
annotate() 的每个参数都是一个annotation,它将添加到返回的QuerySet 中每个对象。
Django 提供的聚合函数在下文的聚合函数文档中讲述。
关键字参数指定的Annotation 将使用关键字作为Annotation 的别名。匿名的参数的别名将基于聚合函数的名称和模型的字段生成。只有引用单个字段的聚合表达式才可以使用匿名参数。其它所有形式都必须用关键字参数。
from django.db.models import Count
q = Blog.objects.annotate(Count('entry'))
q
<QuerySet [<Blog: Beatles Blog>, <Blog: SUN Blog>, <Blog: my blog>, <Blog: my blog>]>
q[0].entry__count # 匿名的参数的别名将基于聚合函数的名称和模型的字段生成
2
q[1].entry__count
0
Blog 模型本身没有定义entry__count 属性,但是通过使用一个关键字参数来指定聚合函数,你可以控制Annotation 的名称:
>>> 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(*fields)
默认情况下,QuerySet 根据模型Meta 类的ordering 选项排序。你可以使用order_by 方法给每个QuerySet 指定特定的排序
随机排序:
Entry.objects.order_by('?')
注:order_by('?') 查询可能耗费资源且很慢,这取决于使用的数据库。
若要按照另外一个模型中的字段排序,可以使用查询关联模型时的语法。即通过字段的名称后面跟上两个下划线(__),再跟上新模型中的字段的名称,直至你希望连接的模型。例如:
Entry.objects.order_by('blog__name', 'headline')
如果Blog 中的Meta设置ordering = ['name'],那么
Entry.objects.order_by('blog')
等同于:
Entry.objects.order_by('blog__name')
通过关联字段排序QuerySet 还能够不用带来JOIN 产生的花费,方法是引用关联字段的_id:
# No Join Entry.objects.order_by('blog_id') # Join Entry.objects.order_by('blog__id')
没有方法指定排序是否考虑大小写。对于大小写的敏感性,Django 将根据数据库中的排序方式排序结果。
你可以通过Lower将一个字段转换为小写来排序,它将达到大小写一致的排序:
Entry.objects.order_by(Lower('headline').desc())
如果你还用到distinct(),在根据关联模型中的字段排序时要小心。distinct() 中有一个备注讲述关联模型的排序如何对结果产生影响。
注
指定一个多值字段来排序结果(例如,一个ManyToManyField 字段或者ForeignKey 字段的反向关联)。
考虑下面的情况:
class Event(Model): parent = models.ForeignKey('self', related_name='children') date = models.DateField() Event.objects.order_by('children__date')
这里,每个Event 可能有多个潜在的排序数据;each Event with multiple children will be returned multiple times into the new QuerySet that order_by() creates. 换句话说, 用 order_by()方法对 QuerySet对象进行操作会返回一个扩大版的新QuerySet对象——新增的条目也许并没有什么卵用,你也用不着它们。
因此,当你使用多值字段对结果进行排序时要格外小心。如果,您可以确保每个订单项只有一个订购数据,这种方法不会出现问题。如果不确定,请确保结果是你期望的
如果你不想对查询做任何排序,即使是默认的排序,可以不带参数调用order_by()。你可以通过检查QuerySet.ordered 属性来知道查询是否是排序的,如果QuerySet 有任何方式的排序它将为True。
每个order_by() 都将清除前面的任何排序。例如,下面的查询将按照pub_date 排序,而不是headline:
Entry.objects.order_by('headline').order_by('pub_date')
reverse
reverse() 方法反向排序QuerySet 中返回的元素。第二次调用reverse() 将恢复到原有的排序。
获取QuerySet 中最后五个元素,你可以这样做:
my_queryset.reverse()[:5]
QuerySet不支持倒着切片,因为无法利用sql高效实现。
同时还要注意,reverse() 应该只在一个已经定义排序的QuerySet 上调用(例如,在一个定义了默认排序的模型上,或者使用order_by() 的时候)。如果QuerySet 没有定义排序,调用reverse() 将不会有任何效果(在调用reverse() 之前没有定义排序,那么调用之后仍保持没有定义)。
distinct
distinct([*fields])
返回一个在SQL 查询中使用SELECT DISTINCT 的新QuerySet。它将去除查询结果中重复的行。
注
order_by() 调用中的任何字段都将包含在SQL 的 SELECT 列中。与distinct() 一起使用时可能导致预计不到的结果。如果你根据关联模型的字段排序,这些fields将添加到查询的字段中,它们可能产生本应该是唯一的重复的行。因为多余的列没有出现在返回的结果中(它们只是为了支持排序),有时候看上去像是返回了不明确的结果。
类似地,如果您使用values()查询来限制所选择的列,则仍然会涉及任何order_by()(或默认模型排序)影响结果的唯一性。
这里的约束是,如果你使用的是distinct(),请注意相关模型的排序。类似地,当一起使用distinct()和values()时,请注意字段在不在values()
values
values(*fields)
返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。
每个字典表示一个对象,键对应于模型对象的属性名称
# 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 应该限制哪些字段。如果指定字段,每个字典将只包含指定的字段的键/值。如果没有指定字段,每个字典将包含数据库表中所有字段的键和值
Blog.objects.values('id', 'name')
<QuerySet [{'id': 3, 'name': 'Beatles Blog'}]>
-
当values() 与distinct() 一起使用时,注意排序可能影响最终的结果。详细信息参见distinct() 中的备注。
-
如果values() 子句位于extra() 调用之后,extra() 中的select 参数定义的字段必须显式包含在values() 调用中。values() 调用后面的extra() 调用将忽略选择的额外的字段。
-
在values() 之后调用only() 和defer() 不太合理,所以将引发一个NotImplementedError。
你可以通过OneToOneField、ForeignKey 和 ManyToManyField 属性反向引用关联的模型的字段:
Blog.objects.values('name', 'entry__headline')
<QuerySet [{'entry__headline': 'this is headline', 'name': 'Beatles Blog'}, {'entry__headline': 'everything is the same', 'name': 'Beatles Blog'}, {'entry__headline': None, 'name': 'SUN Blog'}]>
警告
因为ManyToManyField 字段和反向关联可能有多个关联的行,包含它们可能导致结果集的倍数放大。如果你在values() 查询中包含多个这样的字段将更加明显,这种情况下将返回所有可能的组合
values_list
values_list(*fields, flat=False)
与values() 类似,只是在迭代时返回的是元组而不是字典。每个元组包含传递给values_list() 调用的字段的值 —— 所以第一个元素为第一个字段,以此类推。例如
Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'this is headline'), (2, 'everything is the same')]>
只传递一个字段,你还可以传递flat 参数。如果为True,它表示返回的结果为单个值而不是元组。传递多个字段,传递flat会报错
Entry.objects.values_list('id')
<QuerySet [(1,), (2,)]>
Entry.objects.values_list('id', flat=True)
<QuerySet [1, 2]>
dates
dates(field, kind, order='ASC')
返回DateQuerySet - QuerySet,其计算结果为datetime.date对象列表,表示特定种类的所有可用日期QuerySet。
field应为模型的DateField的名称。 kind应为"year"、"month"或"day"。隐式的是升序排序。若要随机排序,请使用"?",像这样:
- "year" 返回对应该field的所有不同年份值的list。
- “month”返回字段的所有不同年/月值的列表。
- “day”返回字段的所有不同年/月/日值的列表。
Entry.objects.dates('pub_date', 'year')
<QuerySet [datetime.date(2008, 1, 1), datetime.date(2017, 1, 1)]>
Entry.objects.dates('pub_date', 'day')
<QuerySet [datetime.date(2008, 8, 16), datetime.date(2017, 8, 16)]>
Entry.objects.filter(headline__contains='is').dates('pub_date', 'day')
<QuerySet [datetime.date(2008, 8, 16), datetime.date(2017, 8, 16)]>
datetimes
datetimes(field_name, kind, order='ASC', tzinfo=None)
返回QuerySet,其计算为datetime.datetime对象的列表,表示QuerySet内容中特定种类的所有可用日期。
field_name应为模型的DateTimeField的名称。
kind应为“year”,“month”,“day”,“hour”,“minute”或“second”。结果列表中的每个datetime.datetime对象被“截断”到给定的类型。
order, 默认为'ASC', 可选项为'ASC' 或者 'DESC'. 这个选项指定了返回结果的排序方式。
tzinfo定义在截断之前将数据时间转换到的时区。实际上,给定的datetime具有不同的表示,这取决于使用的时区。此参数必须是datetime.tzinfo对象。如果它无,Django使用当前时区。当USE_TZ为False时,它不起作用。
注意
此函数直接在数据库中执行时区转换。因此,您的数据库必须能够解释tzinfo.tzname(None)的值。这转化为以下要求:
- SQLite:install pytz - 转换实际上是在Python中执行的。
- PostgreSQL:没有要求(见时区)。
- Oracle:无要求(请参阅选择时区文件)。
- MySQL:安装pytz,并使用mysql_tzinfo_to_sql加载时区表。
none
none()
调用none()将创建一个从不返回任何对象的查询集,并且在访问结果时不会执行任何查询。qs.none()查询集是EmptyQuerySet的一个实例。
from django.db.models.query import EmptyQuerySet
isinstance(Entry.objects.none(), EmptyQuerySet)
True
all
all()
返回当前QuerySet(或QuerySet 子类) 的副本。它可以用于在你希望传递一个模型管理器或QuerySet 并对结果做进一步过滤的情况。不管对哪一种对象调用all(),你都将获得一个可以工作的QuerySet。
当对QuerySet进行求值时,它通常会缓存其结果。如果数据库中的数据在QuerySet求值之后可能已经改变,你可以通过在以前求值过的QuerySet上调用相同的all() 查询以获得更新后的结果。
select_related
select_related(*fields)
返回一个QuerySet,当执行它的查询时它沿着外键关系查询关联的对象的数据。它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。
一般查询:
# 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
沿着外键查询。如果你有以下模型:
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('author__hometown').get(id=4) 调用将缓存关联的Person 和关联的City:
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. b = Book.objects.get(id=4) # No select_related() in this example. p = b.author # Hits the database. c = p.hometown # Hits the database.
清除QuerySet 上以前的select_related 添加的关联字段,可以传递一个None 作为参数:
without_relations = queryset.select_related(None)
prefetch_related
prefetch_related(*lookups)
返回QuerySet,它将在单个批处理中自动检索每个指定查找的相关对象。
extra
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet修改机制 — 它能在 QuerySet生成的SQL从句中注入新子句
警告
无论何时你都需要非常小心的使用extra(). 每次使用它时,您都应该转义用户可以使用params控制的任何参数,以防止SQL注入攻击。请详细了解SQL injection protection。尽量避免写 extra。
defer
defer(*fields)
在一些复杂的数据建模情况下,您的模型可能包含大量字段,其中一些可能包含大量数据(例如,文本字段),或者需要昂贵的处理来将它们转换为Python对象。如果您在某些情况下使用查询集的结果,当您最初获取数据时不知道是否需要这些特定字段,可以告诉Django不要从数据库中检索它们
only
only(*fields)
only()方法或多或少与defer()相反。您调用它时,应该在检索模型时延迟的字段。如果你有一个模型几乎所有的字段需要延迟,使用only()指定补充的字段集可以导致更简单的代码。
using
using(alias)
如果你使用多个数据库,这个方法用于控制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)
返回一个 queryset ,会锁定相关行直到事务结束。在支持的数据库上面产生一个SELECT ... FORUPDATE语句
例如:
entries = Entry.objects.select_for_update().filter(author=request.user)
所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。
raw
raw(raw_query, params=None, translations=None)
接收一个原始的SQL 查询,执行它并返回一个django.db.models.query.RawQuerySet 实例。这个RawQuerySet实例可以迭代以提供实例对象,就像普通的QuerySet 一样。
更多信息参见执行原始的SQL 查询。
警告
raw() 永远触发一个新的查询,而与之前的filter 无关。因此,它通常应该从Manager 或一个全新的QuerySet 实例调用。
不会返回QuerySets的方法
create
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中有一个你手动设置主键, 并且这个值已经存在于数据库中, 调用 create()将会失败并且触发IntegrityError 因为主键必须是唯一的. 如果你手动设置了主键,做好异常处理的准备.
get_or_create
get_or_create(defaults=None, **kwargs)
返回一个由(object, created)组成的元组,元组中的object 是一个查询到的或者是被创建的对象, created 是一个表示是否创建了新的对象的布尔值(True 表示创建对象,False表示查询到对象)。
这主要用作样板代码的一种快捷方式。例如:
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)})
新对象创建逻辑:
params = {k: v for k, v in kwargs.items() if '__' not in k} params.update(defaults) obj = self.model(**params) obj.save()
使用MySQL,请确保使用READ COMMITTED 隔离级别而不是默认的REPEATABLE READ,否则你将会遇到get_or_create 引发IntegrityError 但对象在接下来的get() 调用中并不存在的情况
get_or_create() 在Django 视图中的使用。请确保只在POST 请求中使用
你可以通过ManyToManyField 属性和反向关联使用get_or_create()。在这种情况下,你应该限制查询在关联的上下文内部。如果你不一致地使用它,将可能导致完整性问题。
根据下面的模型:
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 = 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 “Ulysses” 获取或者创建“Chapter 1”,但是它不能:关联关系不能获取这个chapter 因为它与这个book 不关联,但因为title 字段是唯一的它仍然不能创建。
update_or_create¶
update_or_create(defaults=None, **kwargs)¶
一个通过给出的kwargs 来更新对象的便捷方法, 如果需要的话创建一个新的对象。defaults 是一个由 (field, value) 对组成的字典,用于更新对象。
返回一个由 (object, created)组成的元组,元组中的object 是一个创建的或者是被更新的对象, created 是一个标示是否创建了新的对象的布尔值。
update_or_create 方法尝试通过给出的kwargs 去从数据库中获取匹配的对象。如果找到匹配的对象,它将会依据defaults 字典给出的值更新字段。
这用作样板代码的一种快捷方式。例如:
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()
如果模型的字段数量较大的话,这种模式就变的非常不易用。上面的示例可以用 update_or_create() 重写:
obj, created = Person.objects.update_or_create( first_name='John', last_name='Lennon', defaults=updated_values)
kwargs 中的名称如何解析的详细描述可以参见get_or_create()。
和上文描述的get_or_create() 一样,这个方式容易导致竞态条件,如果数据库层级没有前置唯一性它会让多行同时插入。
in_bulk
in_bulk(id_list)
获取主键值的列表,并返回将每个主键值映射到具有给定ID的对象的实例的字典。
例:
>>> 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
iterator()
评估QuerySet(通过执行查询),并返回一个迭代器(参见 PEP 234)。QuerySet通常在内部缓存其结果,以便在重复计算是不会导致额外的查询。相反,iterator()将直接读取结果,而不在QuerySet级别执行任何缓存(内部,默认迭代器调用iterator()并高速缓存返回值)。对于返回大量只需要访问一次的对象的QuerySet,这可以带来更好的性能和显着减少内存。
请注意,在已经求值了的QuerySet上使用iterator()会强制它再次计算,重复查询。
此外,使用iterator()会导致先前的prefetch_related()调用被忽略,因为这两个优化一起没有意义。
latest
latest(field_name=None)
使用作为日期字段提供的field_name,按日期返回表中的最新对象。
此示例根据pub_date字段返回表中的最新条目:
Entry.objects.latest('pub_date')
如果模型的Meta指定get_latest_by,则可以将field_name参数留给earliest()或者 latest()。默认情况下,Django将使用get_latest_by中指定的字段。
像get(),earliest()和latest() raise DoesNotExist参数。
请注意,earliest()和latest()仅仅是为了方便和可读性。
earliest
earliest(field_name=None)
除非方向更改,否则像latest()。
first
first()
返回结果集的第一个对象, 当没有找到时返回None.如果 QuerySet 没有设置排序,则将会自动按主键进行排序
例:
p = Article.objects.order_by('title', 'pub_date').first()
笔记:first() 是一个简便方法 下面这个例子和上面的代码效果是一样
try: p = Article.objects.order_by('title', 'pub_date')[0] except IndexError: p = None
aggregate(聚合查询)
aggregate(*args, **kwargs)
返回一个字典,包含根据QuerySet 计算得到的聚合值(平均数、和等等)。aggregate() 的每个参数指定返回的字典中将要包含的值。
Django 提供的聚合函数在下文的聚合函数中讲述。因为聚合也是查询表达式,你可以组合多个聚合以及值来创建复杂的聚合。
使用关键字参数指定的聚合将使用关键字参数的名称作为Annotation 的名称。匿名的参数的名称将基于聚合函数的名称和模型字段生成。复杂的聚合不可以使用匿名参数,它们必须指定一个关键字参数作为别名。
例如,当你使用Blog Entry 时,你可能想知道对Author 贡献的Blog Entry 的数目:
>>> 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()
如果QuerySet 包含任何结果,则返回True,否则返回False。它会试图用最简单和最快的方法完成查询,但它执行的方法与普通的QuerySet 查询确实几乎相同。
exists() 用于搜寻对象是否在QuerySet 中以及QuerySet 是否存在任何对象,特别是QuerySet 比较大的时候。
查找具有唯一性字段(例如primary_key)的模型是否在一个QuerySet 中的最高效的方法是:
entry = Entry.objects.get(pk=123) if Blog.objects.filter(pk=entry.pk).exists(): print("Entry contained in queryset")
update
update(**kwargs)
对指定的字段执行SQL更新查询,并返回匹配的行数(如果某些行已具有新值,则可能不等于已更新的行数)。
Entry.objects.filter(pub_date__year=2008).update(headline='update headline')
1
update()方法立即应用,对更新的QuerySet的唯一限制是它只能更新模型主表中的列,而不是相关模型。你不能这样做,例如:
>>> Entry.objects.update(blog__name='foo') # Won't work!
不能在已经计算值QuerySet上调用update(),该查询已截取一个切片,或者无法再进行过滤。
delete
delete()
对QuerySet中的所有行执行SQL删除查询。立即应用delete()。您不能在QuerySet上调用delete(),该查询已采取切片或以其他方式无法过滤。
例如,要删除特定博客中的所有条目:
>>> b = Blog.objects.get(pk=1) # Delete all the entries belonging to this Blog. >>> Entry.objects.filter(blog=b).delete()
默认情况下,Django的ForeignKey模拟SQL约束ON DELETE CASCADE字,任何具有指向要删除的对象的外键的对象将与它们一起被删除。例如:
blogs = Blog.objects.all() # This will delete all Blogs and all of their Entry objects. blogs.delete()
此级联行为可通过ForeignKey的on_delete参数自定义。
delete()方法执行批量删除,并且不会在模型上调用任何delete()方法。但它会为所有已删除的对象(包括级联删除)发出pre_delete和post_delete信号。
Django需要获取对象到内存中以发送信号和处理级联。然而,如果没有级联和没有信号,那么Django可以采取快速路径并删除对象而不提取到内存中。对于大型删除,这可以显着减少内存使用。执行的查询量也可以减少。
设置为on_delete DO_NOTHING的外键不会阻止删除快速路径。
请注意,在对象删除中生成的查询是实施详细信息,可能会更改。
as_manager¶
classmethod as_manager()¶
类方法,返回Manager的实例与QuerySet的方法的副本
字段查找
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';
day
对于日期和日期时间字段,具体到某一天的匹配。取一个整数的天数。
例:
Entry.objects.filter(pub_date__day=3)
SQL等效:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
(确切的SQL语法因每个数据库引擎而异)。
请注意,这将匹配每月第三天(例如1月3日,7月3日等)的任何包含pub_date的记录。
当USE_TZ为True时,在过滤之前,datetime字段将转换为当前时区。这需要数据库中的time zone definitions in the database。
search
一个Boolean类型的全文搜索,以全文搜索的优势。这个很像 contains ,但是由于全文索引的优势,以使它更显著的快。
例:
Entry.objects.filter(headline__search="+Django -jazz Python")
SQL等效:
SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);
注意,这仅在MySQL中可用,并且需要直接操作数据库以添加全文索引,请参阅MySQL文档。
iregex
不区分大小写的正则表达式匹配。
例:
Entry.objects.get(title__iregex=r'^(an?|the) +')
SQL等价物:
SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL
聚合函数
Django 的django.db.models 模块提供以下聚合函数。关于如何使用这些聚合函数的细节,参见聚合函数的指南。关于如何创建聚合函数,参数聚合函数 的文档。
警告
SQLite 不能直接处理日期/时间字段的聚合。这是因为SQLite 中没有原生的日期/时间字段,Django 目前使用文本字段模拟它的功能。在SQLite 中对日期/时间字段使用聚合将引发NotImplementedError。
注
在QuerySet 为空时,聚合函数函数将返回None。 例如,如果QuerySet 中没有记录,Sum 聚合函数将返回None 而不是0。Count 是一个例外,如果QuerySet 为空,它将返回0。
所有聚合函数具有以下共同的参数:
expression
引用模型字段的一个字符串,或者一个查询表达式。
New in Django 1.8:
现在在复杂的计算中,聚合函数可以引用多个字段。
output_field
用来表示返回值的模型字段,它是一个可选的参数。
New in Django 1.8:
添加output_field 参数。
注
在组合多个类型的字段时,只有在所有的字段都是相同类型的情况下,Django 才能确定output_field。否则,你必须自己提供output_field 参数。
**extra
这些关键字参数可以给聚合函数生成的SQL 提供额外的信息。
avg
class Avg(expression, output_field=None, **extra)
返回给定expression 的平均值,其中expression 必须为数值。
- 默认的别名:<field>__avg
- 返回类型:float
Count
class Count(expression, distinct=False, **extra)
返回与expression 相关的对象的个数。
- 默认的别名:<field>__count
- 返回类型:int
有一个可选的参数:
distinct
如果distinct=True,Count 将只计算唯一的实例。它等同于COUNT(DISTINCT <field>) SQL 语句。默认值为False。
Max
class Max(expression, output_field=None, **extra)
返回expression 的最大值。
- 默认的别名:<field>__max
- 返回类型:与输入字段的类型相同,如果提供则为 output_field 类型
Min
class Min(expression, output_field=None, **extra)¶
返回expression 的最小值。
- 默认的别名:<field>__min
- 返回的类型:与输入字段的类型相同,如果提供则为 output_field 类型
StdDev
class StdDev(expression, sample=False, **extra)
返回expression 的标准差。
- 默认的别名:<field>__stddev
- 返回类型:float
有一个可选的参数:
sample
默认情况下,StdDev 返回群体的标准差。但是,如果sample=True,返回的值将是样本的标准差。
SQLite
SQLite 没有直接提供StdDev。有一个可用的实现是SQLite 的一个扩展模块。参见SQlite 的文档 中获取并安装这个扩展的指南。
Sum
class Sum(expression, output_field=None, **extra)
计算expression 的所有值的和。
- 默认的别名:<field>__sum
- 返回类型:与输入的字段相同,如果提供则为output_field 的类型
Variance
class Variance(expression, sample=False, **extra)
返回expression 的方差。
- 默认的别名:<field>__variance
- 返回的类型:float
有一个可选的参数:
sample
默认情况下,Variance 返回群体的方差。但是,如果sample=True,返回的值将是样本的方差。
SQLite
SQLite 没有直接提供Variance。有一个可用的实现是SQLite 的一个扩展模块。 参见SQlite 的文档 中获取并安装这个扩展的指南。
查询相关的类
本节提供查询相关的工具的参考资料,它们其它地方没有文档。
Q() 对象
Prefetch()对象
New in Django 1.7.
class Prefetch(lookup, queryset=None, to_attr=None)
Prefetch()对象可用于控制prefetch_related()的操作。
lookup参数描述了跟随的关系,并且工作方式与传递给prefetch_related()的基于字符串的查找相同。例如:
>>> Question.objects.prefetch_related(Prefetch('choice_set')).get().choice_set.all() [<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() [<Question: Question object>]
查询集参数为给定的查找提供基本QuerySet。这对于进一步过滤预取操作或从预取关系调用select_related()很有用,因此进一步减少查询数量:
>>> voted_choices = Choice.objects.filter(votes__gt=0) >>> voted_choices [<Choice: The sky>] >>> prefetch = Prefetch('choice_set', queryset=voted_choices) >>> Question.objects.prefetch_related(prefetch).get().choice_set.all() [<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() [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
注意
当使用to_attr时,预取的结果存储在列表中。这可以提供比存储在QuerySet实例内的缓存结果的传统prefetch_related调用显着的速度改进。