Django的Manager和QuerySet
要从数据库检索对象,需要通过模型类的 Manager 构建一个 QuerySet。换言之,models,manager和queryset是我们和数据库交互必须的三个东西。 models本身没有什么需要多说的,Django 使用了一套直观的系统:一个模型类代表一张数据表,一个模型类的实例代表数据库表中的一行记录。
模型类的save方法可以插入,更新,删除数据。那么是否可以查询数据呢?实际上由于“一个模型类的实例代表数据库表中的一行记录”,因此模型类的实例是不能起到查询数据的功能。
Manager
因此,我们要从数据库检索到数据,ORM就必须提供相应的方法。在Django中,模型的Manager提供了接口,它赋予了 Django 模型操作数据库的能力。默认情况下,Django 为每个模型类添加了一个名为 objects 的 Manager。
不过,若你想将 objects 用作字段名,或想使用 objects 以外的 Manager 名字,就要在模型基类中重命名。要为指定类重命名 Manager,在该模型中定义一个类型为 models.Manager 的属性。例如:
代码语言:javascript复制from django.db import models
class Person(models.Model):
#...
people = models.Manager() # 自定义名为people的管理器
使用这个实例模型时, Person.objects 会产生一个 AttributeError 异常,而 Person.people.all() 会返回包含所有 Person 对象的列表。
一般而言,我们是不需要自定义manager的。除非以下两种情况:
- 添加额外的 Manager 方法;
- 修改 Manager 返回的原始 QuerySet。
有关如何自定义Manager,在Django管理器中有详细说明。
QuerySet
一个 QuerySet 代表来自数据库中对象的一个集合。它可以有 0 个,1 个或者多个 filters。
可以根据给定参数缩小查询结果量。在 SQL 的层面上, QuerySet 对应 SELECT 语句,而filters对应类似 WHERE 或 LIMIT 的限制子句。
如前所述,你能通过模型的 Manager 获取 QuerySet。每个模型至少有一个 Manager,默认名称是 objects。
需要注意的是Managers 只能通过模型类访问,而不是通过模型实例,目的是强制分离 “表级” 操作和 “行级” 操作。
什么时候QuerySet被执行?
在Django的文档中,明确的告诉了开发者,什么时候QuerySet被执行。因为这影响到SQL执行效率。在这里简要的说明一下,例如下面一段代码:
代码语言:javascript复制>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.date.today())
>>> q = q.exclude(body_text__icontains="food")
>>> print(q)
这段代码看起来好像是做了3次数据库查询,但是实际上并不是。实际只在最后一步print(q)的时候,做了一次数据库查询。因此,通常我们在返回JsonResponse的时候,需要list()函数来强制QuerySet做数据库操作。
细节
代码语言:javascript复制1. 使用len()函数求QuerySet的长度,比起使用QuerySet的count()方法效率要低一些,count()方法实际对应于数据库的聚合函数COUNT,它是数据库层面的操作,而非python。
2. 同理,如果只想知道一个是否存在,可以使用QuerySet的 exences()方法,这比查询出对象本身更高效一些。
3. QuerySet可以被切片,但是不能使用负数索引。使用负数索引会抛出异常:AssertionError: Negative indexing is not supported.
QuerySet 类具有两个可用于自省的公开属性:
可以返回QuerySet对象的QuerySet方法
前文所述的看起来做了3次SQL查询,实际上只有一次。之所以能够实现这样的操作,那是因为上述的方法本身返回的对象依旧是QuerySet对象,而非其它。下面介绍一下常用的可以返回QuerySet对象的QuerySet方法
不能返回QuerySet对象的QuerySet方法
下面介绍一些常用的不能返回QuerySet对象的QuerySet方法。
字段查找
由于字段查询非常多,也非常常用,本文不进行说明。请直接参考Django字段查询
参考资料:
- 执行查询
- QuerySet API参考
- 管理器