在接下来四五篇笔记中,将介绍 model 查询方法的各个细节,为咱们的查问操作提供各种便当。
本篇笔记将介绍惰性查找、filter、exclude、annotate 等办法,目录如下:
- 惰性查找
- filter
- exclude
- annotate
- alias
- order_by
1、惰性查找
后面咱们在介绍 Django 增删改查的时候,提到过他的惰性查找的规定。
也就是说一般的 filter 语句执行时,零碎并不会去查询数据库,只有当咱们真正应用外面的数据的时候,才会去查询数据库。
那么以下介绍几种,应用的时候会查询数据库的状况:
迭代
一个 QuerySet 是可迭代的,而且仅会在第一次迭代的时候查询数据库:
for e in Entry.objects.all():
print(e.headline)
切片
须要留神的是,应用 python 里的切片语法不会拜访数据库,比方:
Entry.objects.all()[:3]
然而,如果应用 step 语法则会拜访数据库,比方以下语句:
Entry.objects.all()[:10:2]
len()
当咱们应用 len() 函数去获取一个 QuerySet 的长度时,会拜访数据库,比方:
len(Entry.objects.all())
然而这种做法是不被举荐的,因为他会把 QuerySet 中的所有数据,都加载进去,而后计算长度。
如果想要获取总数量,咱们会应用另一个函数,.count(),这个咱们前面会提到。
list()
这个操作会强制查询数据库,而后将一个 QuerySet 转换成 python 里的 list。
entry_list = list(Entry.objects.all())
在个别状况下,是不举荐的,因为绝对于 list 而言,QuerySet 能够执行的函数更多。
bool()
判断是否存在数据:
if Entry.objects.filter(headline='hunter'):
print('exists')
然而,在 Django 里个别也不举荐,因为有更高效的用法,那就是应用 .exists() 函数,这个在前面会具体介绍。
2、filter()
filter 这个函数后面都有介绍,能够在其中增加合乎筛选条件,也能够通过链式的模式来操作。
然而链式执行的用法是 and 逻辑,如果想要用 or 逻辑,能够应用 Q() 用法来连用,后面也简略介绍过。
3、exclude()
这个函数与 filter() 函数性能相同,是排除符合条件的数据。
4、annotate()
annotate 这个单词的意思是 正文,在 Django 里的用法是,通过对数据进行解决,比方一个表达式,或者是通过外键引入一个新的数据字段,或者是聚合进去一个后果(比方平均值,综合等),会在每一条返回的数据外面新增一个后面表达式的后果作为一个新的字段返回。
比方咱们获取 Blog 这个 model 的时候,Entry 作为它的外键关系,咱们能够获取关联了某条 Blog 的 Entry 的数量,并且作为新的字段增加到 Blog 里一起返回,其操作如下:
q = Blog.objects.annotate(number_of_entries=Count('entry’))
q[0].number_of_entries
5、alias()
alias() 的用法和 annotate 一样,都能够创立新的数据字段,但与 annotate() 不一样的是,其后果并不会作为一个字段返回,而是用于在应用的过程中做筛选,比方一个用法如下:
q = Blog.objects.alias(number_of_entries=Count('entry')).filter(number_of_entries__gt=1)
6、order_by()
对于 QuerySet 每次返回的后果,如果 Meta 里有 ordering 参数,应用见上一篇 Meta 的应用笔记,那么数据就会依照 ordering 的参数对数据进行排序后返回。
如果 Meta 里没有设置该参数,那么数据则会在有主键 id 的状况下依照 id 的程序返回。
当然,咱们也能够应用 order_by() 这个函数来对每一次搜寻的数据进行排序的重写。
正序排序
比方咱们想要对 Entry 这个 model 对于 pub_date 进行正序排序:
Entry.objects.filter(pub_date__year=2005).order_by('pub_date')
倒序排序
则能够在字段名后面加个 – 负号来操作:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date')
多个字段进行排序
比方 对 pub_date 倒序排序,对 headline 正序排序,则是:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
依照外键字段排序
比方 Entry 这个 model 须要依照外键 Blog 的 name 字段来排序,则通过外键字段 + 双下划线 + 排序字段来实现:
Entry.objects.order_by('blog__name')
如果咱们在查问 Entry 的时候间接依据外键字段,也就是 blog 来排序,Django 会应用 Blog,也就是外键的默认排序(即在 Blog 的 model 的 Meta 里设置的 ordering 来排序),如果外键没有定义默认排序,则会依据主键 id 来排序。
比如说,咱们的 Blog model,如果没有在 Meta 里设置默认的 ordering,那么,上面的语句:
Entry.objects.order_by('blog')
则会等价于:
Entry.objects.order_by('blog_id')
如果在 Blog 的 model 的 Meta 里有设置 ordering=[‘name’],那么则等价于:
Entry.objects.order_by('blog__name')
查问表达式调用 asc() 或者 desc() 办法:
Entry.objects.order_by(Coalesce('summary', 'headline').desc())
asc() 和 desc() 有 nulls_first 和 nulls_last 来管制 null 如何被排序,是放在最开始还是最初面。
疏忽大小写排序
咱们能够通过对字段进行小写解决来达到疏忽大小写排序的目标:
Entry.objects.order_by(Lower('headline').desc())
不排序
如果是不想对数据进行任何排序,则能够间接调用 order_by() 函数,不增加任何参数即可。
Entry.objects.order_by()
不反对链式解决
须要留神的是,不同于 filter() 函数的链式操作,order_by() 是不反对链式操作的,每增加一次 order_by(),后面的排序都会被前面的笼罩。
Entry.objects.order_by('headline').order_by('pub_date')
以上语句则仅会依据 pub_date 进行排序,headline 的排序则会被疏忽。
这个性能如果要验证,很简答,只须要打印出上述语句转换成的 SQL 语句即可。
这个性能在前面的笔记中会介绍到。
以上就是本篇笔记全部内容,接下来将要介绍的是 reverse、distinct、values、values_list 等用法。
本文首发于自己微信公众号:Django 笔记。
原文链接:Django 笔记九之 model 查问 filter、exclude、annotate、order_by
如果想获取更多相干文章,可扫码关注浏览: