Django中用于数据查询的模型.objects
是一个django.db.models.manager.Manager
对象,而Manager
类中的方法,全都来自于QuerySet
类,以下介绍QuerySet
上的一些常用的API。
返回新的QuerySet
使用QuerySet
API进行数据筛选时,方法返回的仍是一个QuerySet
对象,依此可以对API进行链式调用,对数据进行多层筛选。
比如筛选完后还要根据某个字段进行排序,则可以通过链式调用进行:
articles = Article.objects.filter(author__name="abc").order_by("publish_time")
以下介绍返回新的QuerySet
对象的方法:
-
filter
:将满足条件的数据筛选出来,返回新的QuerySet
对象; -
exclude
:排除满足条件的数据,返回一个QuerySet
对象; -
annotate
:给QuerySet
中的每个对象都添加一个使用查询表达式(聚合函数、F表达式、Q表达式)的新字段,返回一个操作后的QuerySet
对象;示例代码:articles = Article.objects.annotate(author_name=F("author__name"))
-
order_by
:将查询结果根据某个字段从小到大排序,若要倒叙排序,则可以在传入字段前加入一个负号。需注意的是,对于多个order_by
的链式调用,会将前面排序的顺序打乱; -
values
:将指定的字段数据提取出来,以"字段名":"字段值"
的键值对存储到字典中。默认情况下会将表中所有的字段全部都提取出来,也可以传入字段名字符串进行指定。此时的QuerySet
结果集中的元素不再是模型,而是字典。articles = Article.objects.values("title","content") for article in articles: print(article)
以上
article
的打印结果是类似于{"title":"abc","content":"abc"}
的形式。 -
values_list
:类似于values
,只不过返回的QuertSet
中,存储的不是多个字典,而是一个元素为("字段值1","字段值2",...)
的列表。如果该元组中只有一个字段,则可以传递参数flat=True
将数据扁平化,此时结果为QuerySet
的结果为["数据1","数据2",...]
。 -
all
:获取ORM
模型的QuerySet
对象,即获取表中的所有数据。 -
select_related
:在提取某个模型的数据时,先将相关联的数据提取出来,则下次访问该关联数据时,不用再重新访问数据库。该方法只能用于使用ForeignKey
字段的模型上,即只能用于一对多,而不能用于多对一或多对多。
如提取文章数据时,可以使用select_related
将作者信息提取出来,以后再次使用artilces.author
时就不需要再次访问数据库,可以减少数据库查询次数:article = Article.objects.get(pk=1) >> article.author # 重新执行一次查询语句 article = Article.objects.select_related("author").get(pk=2) >> article.author # 不需要重新执行查询语句
select_related
在取数据前调用。 -
prefetch_related
:与prefetch_related
类似,不过是用于一对多或多对多的情况,即关联的模型有多个的时候。
如想要获取一个作者下的所有文章:authors = Author.objects.prefetch_related("article_set").filter(name="wjiaman")
即如查询关联模型集一样,传入字符串
模型__set
,而若在返回的QuerySet
对象上调用方法创建一个新的QuerySet
,则会将之前的SQL破坏掉:for author in authors: print(author.article.filter(title="abc")) #filter方法会生成一个新的QuerySet对象
-
defer
:过滤掉表中不需要的字段,提高查询的效率,此时若调用在返回的模型实例上访问该字段,则会重新向数据库中进行一次查找操作。注意defer
不能过滤id
字段。
示例代码:articles = Article.objects.defer("title") for article in articles: print(article.title) #此时将重新向数据库进行一次查找操作
-
only
:与defer
类似,只不过defer
时过滤掉指定字段,而only
是只提取指定字段。only
与values
的区别是返回的QuerySet
对象中存储的是模型实例,而values
的QuerySet
中存储的是字典。 -
get
:获取一条数据,该方法要求待筛选的数据在数据库中有且仅有一条。 -
create
:创建一条数据,保存到数据库中。该方法相当于先用指定的模型创建一个对象,然后再调用该对象的.save()
方法。
示例代码:article = Article.objects.create(title='abc')
-
get_or_create
:根据某个条件进行查找,如果找到了则返回这条数据,如果没有找到则创建这条数据。 -
bulk_create
:传入一个模型实例列表,一次性创建多个数据。
示例代码:Article.objects.bulk_create([ Article(title="abc"), Article(title="bcd"), ])
-
count
:获取提取的数据的个数。如果想要知道总共有多少条数据,则建议使用count
,而非len(articles)
。因为count
在底层是使用select count(*)
实现的,该方式比将所有数据从数据库中提取出来后再使用len
函数更加高效。 -
first
和last
:返回QuerySet
中的第一条或最后一条数据。 -
aggregate
:使用聚合函数 -
exists
:判断某个条件的数据是否存在。如果要判断符合某条件的数据是否存在,则建议使用exists
,该法比使用count
或直接判断QuerySet
是否为空更有效。 -
distinct
:去除掉重复的数据。 -
update
:数据更新操作。 -
delete
:删除所有满足条件的数据。 -
切片操作:在
QuerySet
对象上也可进行切片操作。且在数据选择时的切片操作并不是把所有数据从数据库中提取出来再做切片操作,而是在数据库层面使用LIMIE
和OFFSET
来帮完成。
什么时候会执行SQL语句
生成一个QuerySet
对象并不会马上转换为并不会马上转换为SQL语句取执行,只有在以下情况下QuerySet
才会转换为SQL
执行:
- 迭代:在遍历
QuerySet
对象时,会先执行这个SQL语句,然后再将结果返回进行迭代。for article in Articles.objects.all(): print(article.title)
- 使用步长的切片操作:对
QuerySet
对象做切片操作本身不会执行SQL语句,但是若在切片操作时提供了步长,则会立马执行SQL语句。即切片操作的结果是QuerySet
对象,带步长的切片操作返回实际的数据。需注意的是,带步长的切片操作后不能再使用查询操作。 - 调用
len
函数:调用len
函数获取QuerySet
中的数据数时也会执行SQL语句。 - 调用
list
函数:调用list
函数将QuerySet
对象转换为列表对象也会立马执行SQL语句。 - 判断:若对某个
QuerySet
进行判断,会立即执行SQL语句。
即创建
QuerySet
对象时不会马上执行SQl语句,从QuerySet
对象中获取具体的信息时才会执行SQL。