QuerySet API参考

本文档描述了QuerySet API的详细信息。它建立在模型数据库查询指南的基础上,所以在阅读本文档之前,你也许需要首先阅读这两部分的文档。

本文档将通篇使用在数据库查询指南中用到的Weblog 模型的例子

何时对查询集求值(要写到程序里的字段麻烦不要自作聪明翻译谢谢)

在内部,可以创建、过滤、切片和传递查询集而不用真实操作数据库。在你对查询集做求值之前,不会发生任何实际的数据库操作。

你可以使用下列方法对查询集求值:

  • 迭代。queryset是可迭代的,它在首次迭代查询集时执行实际的数据库查询。例如, 下面的语句会将数据库中所有Entry 的headline 打印出来:

    for e in Entry.objects.all():
        print(e.headline)
    

    注意:不要使用上面的语句来验证在数据库中是否至少存在一条记录。使用 exists()方法更高效。

  • 切片。 正如在限制查询集中解释的那样, 可以使用Python 的序列切片语法对一个查询集进行分片。一个未求值的查询集进行切片通常返回另一个未求值的查询集,但是如果你使用切片的”step“参数,Django 将执行数据库查询并返回一个列表。对一个已经求值的查询集进行切片将返回一个列表。

    还要注意,虽然对未求值的查询集进行切片返回另一个未求值的查询集,但是却不可以进一步修改它了(例如,添加更多的Filter,或者修改排序的方式),因为这将不太好翻译成SQL而且含义也不清晰。

  • 序列化/缓存。 序列化查询集的细节参见下面一节。本节提到它的目的是强调序列化将读取数据库。

  • repr()。 当对查询集调用repr() 时,将对它求值。这是为了在Python 交互式解释器中使用的方便,这样你可以在交互式使用这个API 时立即看到结果。

  • len()。 当你对查询集调用len() 时, 将对它求值。正如你期望的那样,返回一个查询结果集的长度。

    注:如果你只需要知道集合中记录的个数(并不需要真实的对象),使用数据库层级的SELECT COUNT(*) 计数将更加高效。为此,Django 提供了 一个count() 方法.

  • list()。查询集调用list() 将强制对它求值。例如:

    entry_list = list(Entry.objects.all())
    
  • bool()。 测试一个查询集的布尔值,例如使用bool()orand 或者if 语句将导致查询集的执行。如果至少有一个记录,则查询集True,否则为False。例如:

    if Entry.objects.filter(headline="Test"):
       print("There is at least one Entry with the headline Test")
    

    注:如果你需要知道是否存在至少一条记录(而不需要真实的对象),使用 exists() 将更加高效。

Pickle 查询集

如果你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 的结果

查询集的Pickle 只能用于生成它们的Django 版本中。如果你使用Django 的版本N 生成一个Pickle,不保证这个Pickle 在Django 的版本N+1 中可以读取。Pickle 不可用于归档的长期策略。

New in Django 1.8.

因为Pickle 兼容性的错误很难诊断例如产生损坏的对象,当你试图Unpickle 的查询集与Pickle 时的Django 版本不同,将引发一个RuntimeWarning

查询集 API

下面是对于查询集的正式定义:

class QuerySet([model=None, query=None, using=None])[source]

通常你在使用QuerySet时会以链式的filter 来使用。为了让这个能工作,大部分QuerySet 方法返回新的QuerySet。这些方法在本节将详细讲述。

QuerySet 类具有两个公有属性用于内省:

ordered[source]

如果QuerySet 是排好序的则为True —— 例如有一个order_by() 子句或者模型有默认的排序。否则为False .

db[source]

如果现在执行,则返回将使用的数据库。

QuerySet 存在query 参数是为了让具有特殊查询用途的子类如GeoQuerySet 可以重新构造内部的查询状态。这个参数的值是查询状态的不透明的表示,不是一个公开的API。简而言之:如果你有疑问,那么你实际上不需要使用它。

返回新的查询集 的方法(要写到程序里的字段麻烦不要自作聪明翻译谢谢)

Django 提供了一系列 的QuerySet筛选方法,用于改变 QuerySet 返回的结果类型或者SQL查询执行的方式。

filter

filter(**kwargs)

返回一个新的QuerySet,包含与给定的查询参数匹配的对象。

查找的参数(**kwargs)应该满足下文字段查找中的格式。在底层的SQL 语句中,多个参数通过AND 连接。

如果你需要执行更复杂的查询(例如,使用OR 语句查询),你可以使用Q 对象

exclude

exclude(**kwargs)

返回一个新的QuerySet,它包含满足给定的查找参数的对象。

查找的参数(**kwargs)应该满足下文字段查找中的格式。 在底层的SQL 语句中,多个参数通过AND 连接,然后所有的内容放入NOT() 中。

下面的示例排除所有pub_date 晚于2005-1-3 且headline 为“Hello” 的记录:

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 或者headline 为“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 对象

annotate

annotate(*args, **kwargs)

使用提供的查询表达式Annotate 查询集中的每个对象。查询表达式可以是一个简单的值、模型(或关联模型)字段的一个引用或对查询集中的对象一个聚合函数(平均值、和等)。

New in Django 1.8:

之前版本的Django 值允许聚合函数用作Annotation。现在可以使用各种表达式annotate 一个模型。

annotate() 的每个参数都是一个annotation,它将添加到返回的QuerySet 中每个对象。

Django 提供的聚合函数在下文的聚合函数文档中讲述。

关键字参数指定的Annotation 将使用关键字作为Annotation 的别名。匿名的参数的别名将基于聚合函数的名称和模型的字段生成。只有引用单个字段的聚合表达式才可以使用匿名参数。其它所有形式都必须用关键字参数。

例如,如果你正在操作一个Blog 列表,你可能想知道每个Blog 有多少Entry:

>>> 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 属性,但是通过使用一个关键字参数来指定聚合函数,你可以控制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.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

上面的结果将按照pub_date 降序排序,然后再按照headline 升序排序。"-pub_date" 前面的负号表示降序排序。隐式的是升序排序。若要随机排序,请使用"?",像这样:

Entry.objects.order_by('?')

注:order_by('?') 查询可能耗费资源且很慢,这取决于使用的数据库。

若要按照另外一个模型中的字段排序,可以使用查询关联模型时的语法。即通过字段的名称后面跟上两个下划线(__),再跟上新模型中的字段的名称,直至你希望连接的模型。&#x