Model 层 QuerySet 的使用
Model作为MVC模式中的基础层(数据层)负责为整个系统提供数据。- 在Model层中,
Django通过给Model增加一个objects属性来提供数据操作的接口。比如想要查询所有文章的数据,可以这么写:xxx.objects.all(),这样就能拿到QuerySet对象。这个对象包含了我们需要的数据,当我们用到他时,它会去DB中获取数据 - 就是用到数据时才会去DB中查询,而不是执行
xxx.objects.all()时去执行数据库查询语句的,原因是QuerySet要支持链式操作。如果每次执行都要查询数据库的话,会存在性能问题,因为你可能用不到你执行的代码,所以QuerySet是懒加载的 - 链式调用:执行一个对象的方法之后得到的结果还是这个对象,这样可以接着执行对象的其他方法。例如:
posts = Post.objexts.filter(status=1).filter(category_id=2)
常用的QuerySet接口
- 支持链式调用的接口
-
all接口,相当于SELECT * FROM table_name语句,用于查询所有数据 -
filter接口,根据条件过滤数据,常用的条件基本上是字段等于、不等于、大于、小于。还有能改成LIKE查询的:Model.objects.filter(content__contains="条件") -
exclude接口,同filter,只是相反的逻辑 -
reverse接口,把QuerySet中的结果倒序排列 -
distinct接口,用来进行去重查询,产生SELECT DISTINCT这样的SQL查询 -
none接口,返回空的QuerySet
-
- 不支持链式调用的接口
不支持链式调用的接口即返回值不是QuerySet的接口-
get接口,例如Post.objects.get(id=1)用于查询id为1的文章,存在则返回实例,不存在则抛出异常 -
create接口,用来直接创建一个Model对象 -
get_or_create接口,根据条件查找,如果没有查找到,就调用create调用 - update_or_create 接口,同get_or_create,只是用来做更新操作
-
count接口,返回QuerySet有多少条记录 -
latest接口,返回最新的一条记录,需要在Meta中定义:get_latest_by = <用来排序的字段> -
earliest接口,返回最早的一条记录 -
first接口,从当前QuerySet记录中获取第一条 -
last接口,同上,获取最后一条 -
exists接口,判断QuerySet是否有数据,返回True或False -
bulk_create接口,同create,用来批量创建记录 -
in_bulk接口,批量查询,接收两个参数id_list和field_name -
update接口,根据条件批量更新记录 -
delete接口,同update,根据条件批量删除记录 -
values接口,当我们只需要返回某个字段的值,不需要Model实例时,可以使用,用法:title_list = Post.objects.filter(category_id=1).values('title') -
values_list接口,同values,直接返回包含tuple的QuerySet
-
进阶接口
-
defer接口,把不需要展示的字段做延迟加载。比如说,需要获取到文章中除正文外的其他字段,就可以通过posts = Post.objects.all().defer('content'),这样拿到的记录就不会包含content部分,但是当我们需要用到这个字段时,在使用时会去加载 -
only接口,同defer接口刚好相反,如果只想获取到所有的title记录,就可以使用only,只获取title的内容,其他值在获取时会产生额外的查询 -
select_related接口,用来解决外键产生的N+1问题的方案,只能解决一对多的关系 -
prefetch_related接口,针对多对多关系的数据,可以通过这个接口来避免N+1查询
常用的字段查询
Post.objects.filter(content__contains='查询条件') 中的contains就属于字段查询。以下是常用的查询关键字
-
contains: 包含,用来进行相似查询 -
icontains: 同contains,只是忽略大小写 -
exact: 精准匹配 -
iexact: 同exact,忽略大小写 -
in: 指定某个集合 -
gt: 大于某个值 -
gte: 大于等于某个值 -
lt: 小于某个值 -
lte: 小于等于某个值 -
startswith: 以某个字符串开头,与contains类似,只是会产生LIKE '<关键字>%'这样的SQL -
istartswith: 同startswith,忽略大小写 -
endswith: 以某个字符串结尾 -
iendswith: 同endswith,忽略大小写 -
range: 范围查询,多用于时间范围
进阶查询
用来满足更复杂的查询
- F : F表达式常用来执行数据库层面的计算,从而避免出现竞争状态,比如需要处理每篇文章的访问量,假设存在
post.pv这样的字段,当有用户访问时,我们对其加1:
post = Post.objects.get(id=1)
post.pv = post.pv + 1
post.save()
这在多线程的情况下会出现问题,如果多个线程同时执行了 post = Post.objects.get(id=1) ,那么每个线程的post.pv值都是一样的,执行完加1和保存之后,相当于只执行了一个加1,而不是多个。这时通过 F 表达式就可以方便的解决这个问题:
from django.db.models import F
post = Post.objects.get(id=1)
post.pv = F('pv') + 1
post.save()
- Q :
Q表达式就是用来解决OR查询的,用法:
from django.db.models import Q
Post.objects.filter(Q(id=1) | Q(id=2))
或者 AND 查询:
Post.objects.filter(Q(id=1) & Q(id=2))
- Count : 用来做聚合查询,比如想要得到某个分类下有多少篇文章:
简单做法:
category = Category.objects.get(id=1)
post_count = category.post_set.count()
但是如果项把这个结果放到category上,通过category.post_count可以访问到呢:
from django.db.models import Count
categories = Category.objects.annotate(post_count=Count('post'))
print(categories[0].post_count)
这相当于给category动态增加了属性post_count,而这个属性的值来源于Count('post'),annotate用来给QuerySet结果增加属性
- Sum : 同
Count类似,只是她是用来做合计的。比如想要统计目前所有文章加起来的访问量有多少:
from django.db.models import Sum
Post.objects.aggregate(all_pv)=Sum('pv'))
# 输出类似结果:{ 'all_pv': 487 }
aggregate用来直接计算结果
除了Count和Sum外,还有Avg、Min和Max等表达式,均用来满足我们对SQL查询的需求

本文详细介绍了Django Model层的QuerySet使用,包括常用和进阶接口,如filter、exclude、order_by等,以及各种字段查询方式,如contains、startswith等。还探讨了F表达式和Q表达式的高级查询技巧,用于处理数据库计算和复杂查询条件。
16万+

被折叠的 条评论
为什么被折叠?



