在接下来四五篇笔记中,将介绍 model 查询方法的各个细节,为我们的查询操作提供各种便利。
本篇笔记将介绍惰性查找、filter、exclude、annotate等方法,目录如下:
前面我们在介绍 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() 函数,这个在后面会详细介绍。
filter 这个函数前面都有介绍,可以在其中添加符合筛选条件,也可以通过链式的形式来操作。
但是链式执行的用法是 and 逻辑,如果想要用 or 逻辑,可以使用 Q() 用法来连用,前面也简单介绍过。
这个函数与 filter() 函数功能相反,是排除符合条件的数据。
annotate 这个单词的意思是 注释,在 Django 里的用法是,通过对数据进行处理,比如一个表达式,或者是通过外键引入一个新的数据字段,或者是聚合出来一个结果(比如平均值,综合等),会在每一条返回的数据里面新增一个前面表达式的结果作为一个新的字段返回。
比如我们获取 Blog 这个 model 的时候,Entry 作为它的外键关系,我们可以获取关联了某条 Blog 的 Entry 的数量,并且作为新的字段添加到 Blog 里一起返回,其操作如下:
q = Blog.objects.annotate(number_of_entries=Count('entry’))
q[0].number_of_entries
alias() 的用法和 annotate 一样,都可以创建新的数据字段,但与 annotate() 不一样的是,其结果并不会作为一个字段返回,而是用于在使用的过程中做筛选,比如一个用法如下:
q = Blog.objects.alias(number_of_entries=Count('entry')).filter(number_of_entries__gt=1)
对于 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 语句即可。
如果查看 Django 的 QuerySet 转换的 SQL 代码,以前写过一篇博客,可以参考:https://blog.csdn.net/weixin_43354181/article/details/102881471
以上就是本篇笔记全部内容,接下来将要介绍的是 reverse、distinct、values、values_list 等用法。
本文首发于本人微信公众号:Django笔记。
原文链接:Django笔记九之model查询filter、exclude、annotate、order_by
如果想获取更多相关文章,可扫码关注阅读:

这似乎应该有一个直截了当的答案,但在Google上花了很多时间,所以我找不到它。这可能是缺少正确关键字的情况。在我的RoR应用程序中,我有几个模型共享一种特定类型的字符串属性,该属性具有特殊验证和其他功能。我能想到的最接近的类似示例是表示URL的字符串。这会导致模型中出现大量重复(甚至单元测试中会出现更多重复),但我不确定如何让它更DRY。我能想到几个可能的方向...按照“validates_url_format_of”插件,但这只会让验证干给这个特殊的字符串它自己的模型,但这看起来很像重溶液为这个特殊的字符串创建一个ruby类,但是我如何得到ActiveRecord关联这个类模型
是否有可能:before_filter:authenticate_user!||:authenticate_admin! 最佳答案 before_filter:do_authenticationdefdo_authenticationauthenticate_user!||authenticate_admin!end 关于ruby-on-rails-before_filter运行多个方法,我们在StackOverflow上找到一个类似的问题: https://
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
我已经搜索过这个问题的答案,但没有成功,有一个类似的问题,但答案在这种情况下不起作用,它按数字项目排序。SimilarQuestion-Thatdidnotwork我正在尝试使用ruby的sort_by对一个项目进行降序排序和另一个升序排序。我只能找到一个。代码如下:#PrimarysortLastNameDescending,withtiesbrokenbysortingAreaofinterest.people=people.sort_by{|a|[a.last_name,a.area_interest]}任何指导肯定会有所帮助。示例数据:输入罗素,逻辑欧拉,图论伽罗瓦,抽象代
ActiveRecord用于在每次调用保存方法时调用after_save回调,即使模型没有更改并且没有生成插入/更新查询也是如此。这实际上是默认行为。在大多数情况下这没问题。但是一些after_save回调对模型是否实际保存的事情很敏感。有没有办法确定模型是否实际保存在after_save中?我正在运行以下测试代码:classStage 最佳答案 ActiveRecordusetocallafter_savecallbackeachtimesavemethodiscalledevenifthemodelwasnotchangedan
我在我的Rails项目中使用rspec_rails和factory_girl_railsgem。所有模型都已创建。是否有我可以运行的生成器来为现有模型创建工厂文件?例如:我已经有了一个Blog模型。RSpec允许我通过简单地运行以下命令在spec/models/blog_spec.rb生成一个模型规范文件:railsgeneraterspec:modelblog是否有我可以在命令行中运行的生成器,它会为这个现有模型生成工厂文件,位于:spec/factories/blogs.rb?我在factory_girl_rails中没有看到任何关于发电机的提及文档。
在我的Controller中,我得到了按类别分组的所有Extras:defindex@categories=Extra.all.group_by(&:category)end结果类似于哈希数组:{#=>[#,#=>[#,#]}我想按类别“排序”列而不是id排序,它应该如下所示:{#=>[#,#=>[#,#]}当我尝试时:defindex@categories=Extra.all.group_by(&:category).sort_by{|s|s[:sort]}end我得到“没有将符号隐式转换为整数”。那是因为我在“sort_by”中使用了一个符号吗? 最佳答
在Ruby(或Rails)中,我们可以做到new_params=params.merge({:order=>'asc'})现在new_params是一个带有添加键:order的散列。但是是否有一行可以返回带有已删除key的散列?线路new_params=params.delete(:order)不会工作,因为delete方法返回值,仅此而已。我们必须分3步完成吗?tmp_params=paramstmp_params.delete(:order)returntmp_params有没有更好的方法?因为我想做一个new_params=(params[:order].blank?||para
我的应用程序有一个名为User的模型(它包括电子邮件地址、用户名……)我想创建一个模型Message它应该有两个字段sender和recipient。两者都是对User模型的引用。我试过这个:railsgeneratemodelMessagesender:referencesrecipient:referencesRails生成了这个:classMessage但我不想要两种不同的模型。这两个字段都应引用User。我正在运行Ruby2.0.0和Rails4.0.2。非常感谢任何帮助。如果您需要有关我的问题的更多信息,请询问我。 最佳答案
我有一个以时间戳为键的哈希。hash={"2016-05-31T22:30:58+02:00"=>{"path"=>"/","method"=>"GET"},"2016-05-31T22:31:23+02:00"=>{"path"=>"/tour","method"=>"GET"},"2016-05-31T22:31:05+02:00"=>{"path"=>"/contact_us","method"=>"GET"}}我订购了这个系列并得到了第一双这样的:hash.sort_by{|k,_|k}.first.first但是我该如何删除它呢?删除方法requiresyou知道key的准确