Django 2.1.3 文档-模型层-QuerySet 方法参考

译自官方文档+自己的理解

本文档描述了QuerySetAPI 的详细信息。它建立在 模型数据库查询 指南中提供的材料之上,因此在阅读本文档之前,您可能希望阅读并理解这些文档。

在整个参考文献中,我们将使用数据库查询指南中提供的示例Weblog模型。

1.什么时候QuerySet求值

本质上,QuerySet可以构造,过滤,切片,并且通常可以在不实际访问数据库的情况下传递。在您对queryset求值之前,实际上不会发生任何数据库活动。

您可以通过以下方式对QuerySet求值 :

(1)迭代。一个QuerySet是可迭代的,并且在您第一次迭代它时执行其数据库查询。例如,这将打印数据库中所有书籍的名称:

for e in Book.objects.all():
    print(e.name)

注意:如果您只想确定是否存在至少一个结果,请不要使用此选项。使用exists()效率更高。

>>>Book.objects.exists()
True

(2)切片。如 限制查询集 中所述,可以使用Python的数组切片语法对QuerySet进行切片。切片未评估的 QuerySet通常会返回另一个未评估的值QuerySet,但如果使用切片语法的“step”参数,Django将执行数据库查询,并返回一个列表。QuerySet对已经过评估的切片也会返回一个列表。

还要注意,即使对未评估的QuerySet切片返回另一个未评估QuerySet,进一步修改它(例如,添加更多过滤器,或修改排序)是不允许的,因为这不能很好地转换为SQL,它也没有明确的含义。

(3)腌制/缓存。有关腌制QuerySets时所涉及的内容的详细信息,请参阅以下部分。对于本节而言,重要的是从数据库中读取结果。

(4)repr()。在QuerySet上调用repr()方法进行求值,这是为了方便Python交互式解释器,因此您可以在交互式使用API​​时立即看到结果。

(5)len()。在QuerySet上调用len()方法进行求值. 正如您所料,这会返回结果列表的长度。

注意:如果您只需要确定集合中的记录数(并且不需要实际对象),那么使用SQL处理数据库级别的计数方法SELECT COUNT(*)会更有效。Django 正是出于这个原因提供了一种count()方法。

(6)list()。在QuerySet上调用list()方法进行求值。
例子:

def fun05_queryset_api():
    print(Book.objects.exists())
    print(repr(Book.objects.all()))
    print(len(Book.objects.all()))
    print(Book.objects.all().count())
    print(list(Book.objects.all()))
# 输出结果
<QuerySet [<Book: <呐喊>>, <Book: <哈利波特>>, <Book: <灭亡>>, <Book: <中国文人集>>]>
4
4
[<Book: <呐喊>>, <Book: <哈利波特>>, <Book: <灭亡>>, <Book: <中国文人集>>]

(7)bool()。测试QuerySet在布尔上下文中,如使用 bool(),or,and或if语句,将导致查询被执行。如果至少有一个结果,QuerySet则为 True,否则False。例如:

if Book.objects.filter(name__contains="呐"):
   print("There is at least one Book with the name contains 呐")

注意:如果您只想确定是否存在至少一个结果(并且不需要实际对象),则使用exists()会更有效。

2. 腌制(pickling)QuerySets

如果腌制 (pickle) 一个QuerySet,这将强制所有结果在腌制之前加载到内存中。腌制通常用作缓存的前身,并且当重新加载缓存的查询集时,您希望结果已经存在并且可以使用(从数据库读取可能需要一些时间,从而无法实现缓存)。这意味着当你取消腌制(unpickle)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的一部分。但是,如此处所述,对属性的内容进行pickle和unpickle是安全的(并且完全支持)。

您无法在版本之间共享pickles数据

腌制 QuerySets仅对用于生成它们的Django版本有效。如果使用Django版本N生成pickle,则无法保证使用Django版本N + 1可以读取pickle。腌制数据不应该用作长期存档的策略。

由于pickle兼容性错误很难诊断,例如无提示损坏的对象,因此当您尝试在Django版本中取消查询不同于其被pickle的查询集时,会引发RuntimeWarning错误。

3. QuerySet API

这是一个正式的QuerySet声明:

class QuerySet(model = None,query = None,using = None)源代码
通常,当您与一个QuerySet进行交互时,您将通过 过滤器链 来使用它 。为了使其工作,大多数 QuerySet方法返回新的查询集。本节稍后将详细介绍这些方法。

该QuerySet 类有可用于内省的两个公共属性:

(1)ordered
如果QuerySet是有序的返回True - 即在模型上有一个order_by()子句或默认排序;否则返回False。

(2)db
现在执行此查询时将使用的数据库。

注解

QuerySet存在一个query参数,以便专门的查询子类可以重建内部查询状态。参数的值是该查询状态的不透明表示,并且不是公共API的一部分。简单地说:如果你需要问,你不需要使用它。

print(Book.objects.all().ordered)
print(Book.objects.order_by('name').ordered)
print(Book.objects.all().db)
print(Book.objects.all().query)
# 输出结果
False
True
default
SELECT "filter_book"."id", "filter_book"."name", "filter_book"."price", "filter_book"."category", "filter_book"."publishs_id" FROM "filter_book"

3.1 返回新QuerySets的方法

Django提供了一系列QuerySet细化方法,可以修改由其返回QuerySet的结果类型或执行SQL查询的方式。

filter()

filter(** kwargs)
返回一个QuerySet,包含与给定查找参数匹配的所有对象。

查询参数(**kwargs)应采用下面的字段查找中描述的格式 。多个参数通过AND在底层SQL语句中连接起来。

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

exclude()

exclude(** kwargs)
返回一个QuerySet,包含与给定查找参数匹配的所有对象。

查询参数(**kwargs)应采用下面的字段查找中描述的格式 。多个参数通过AND在底层SQL语句中连接起来,整个事件都包含在一个NOT()中。

此示例排除所有价格小于30并且书名包含“呐喊”的书籍:

print(Book.objects.exclude(price__lt=30,name__contains="呐喊"))
# 输出结果
<QuerySet [<Book: <哈利波特>>, <Book: <灭亡>>, <Book: <中国文人集>>]>

在SQL术语中,转化为:

SELECT ...
  WHERE
  NOT ("filter_book"."name" LIKE '%呐喊%' 
  AND "filter_book"."price" < 30)

此示例排除所有价格小于30或者书名包含“呐喊”的书籍::

print(Book.objects.exclude(price__lt=30).exclude(name__contains="呐喊"))
# 输出结果
<QuerySet [<Book: <哈利波特>>, <Book: <中国文人集>>]>

在SQL术语中,评估为:

SELECT ...
FROM "filter_book"
WHERE (NOT ("filter_book"."price" < 30)
AND
NOT ("filter_book"."name" LIKE '%呐喊%' )

请注意,第二个示例更具限制性。

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

annotate()

annotate(* args,** kwargs)

猜你喜欢

转载自blog.csdn.net/lengfengyuyu/article/details/84503546
今日推荐