基本概念
在Django的Model层,Django通过给Model增加一个objects属性来提供数据操作的接口.
例如,我们想获取所有学生的所有信息,可以写成Student.objects.all()
,这样我们就能拿到QuerySet对象.这个对象包含了我们需要的数据,当我们用到时,它才会去数据库中获取数据。
也就是说,QuerySet本质上是懒加载
的对象,这也是因为QuerySet要支持链式调用。
链式调用:执行一个对象中的方法后得到的结果还是这个对象,这样可以接着执行对象上的其他方法。
支持链式调用的接口
支持链式调用的接口即返回QuerySet的接口:
- all : 用于查询所有数据
- filter : 条件过滤
- exclude :类似filter,只不过是相反的逻辑,不满足条件的
- reverse : 把QuerySet中的结果倒序排列
- distinct : 去重
- none : 返回空的QuerySet
不支持链式调用的接口
- get : 比如Student.objects.get(id=1),用于查询id为1的学生信息,如果存在,则直接返回对应的Student实例;如果不存在,则抛出DoesNotExist异常,所以一般会做异常处理
1
2
3
4try:
student = Student.objects.get(id=1)
except Student.DoesNotExist:
pass - create : 直接创建一个model对象。比如
student = Student.objects.create(name="小明")
- get_or_create : 根据条件查找,如果没有找到就创建
- update_or_create :更新或新建
- count : 用于返回QuerySet有多少条记录
- latest : 返回最新的一条记录,但是需要在model中的Meta中定义:
get_lastest_by=用来排序的字段
- earliest : 返回最早的一条记录
- first : 从当前QuerySet记录中获取第一条
- last : 同上,返回最后一条
- exists : 返回True或者False,判断符合条件的数据是否存在
- bulk_create : 批量创建记录
- in_bulk : 批量查询,接受两个参数
id_list
和filed_name
。可以通过Student.objects.in_bulk([1,2,3])查询出id为1,2,3的数据,返回结果是字典类型,字典的key为查询条件。返回结果示例{1:<实例1>,2:<实例2>,3:<实例3>,}
- update : 根据条件批量更新记录
- delete : 根据条件批量删除。
注意!update和delete都会触发Django的signal
- values : 只返回某个字段的值。返回的结果是包含dict的QuerySet
- values_list : 返回包含元组的QuerySet,如果只是一个字段的话,可以通过
flat=True
,变为一维数组
不常用但可能会很有效的接口
- defer : 把不需要展示的字段做延迟加载。例如不想加载某个过大的字段,就可以使用defer
- only : 只加载指定字段
- select_related : 通常用来解决外键产生的N+1的问题。只能用来解决一对多的关联关系
N+1问题:一条查询请求返回N条数据,当我们操作数据时,又会产生额外的请求,这就是N+1问题,所有的ORM框架都存在这样的问题。通常由外键查询产生。
1
2
3
4# 假设学生表和老师表通过外键关联,一对多关系
students = Student.objects.all()
for s in students: # 产生数据库查询
print(s.teacher_name) # 需要再次查询这种问题的解决方法就是使用select_related
1
2
3students = Student.objects.all().select_related("teacher_name")
for s in students: # 产生数据库查询,教师名字也会被一并查出
print(s.teacher_name) - prefetch_related : 针对多对多关系的数据。
1
2
3
4# 假设学生表和老师表通过外键关联,多对多关系
students = Student.objects.all().prefetch_related("teacher")
for s in students:
print(s.teacher.all()
常用的字段查询
- contains : 包含,用来相似查询
- icontains : 同上,只是忽略大小写
- exact : 精确匹配
- in : 指定某个集合
- gt : 大于
- gte : 大于等于
- lt : 小于
- lte : 小于等于
- startswith : 以某个字符串开始
- endswith : 以某个字符串结束
- istartswith : 忽略大小写
- iendswith : 忽略大小写
- range : 范围查询,多用于时间。例如
Info.objects.filter(created_time__range=('2019-01-01','2020-01-01'))
F查询
F查询主要用来执行数据库层面的计算,从而避免出现竞争状态。
比如处理文章的访问量:
1 | from django.db.models import F |
也可以用来直接比较值
1 | # 查询评论数小于收藏数的书籍 |
Q查询
filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q对象。
你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询
1 | from django.db.models import Q |
查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将”AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:
1 | bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python") |
一些有助于理解的样例
1 | # 查询评论数大于阅读数的书籍 |