「Django框架」QuerySet详解

 Django中用于数据查询的模型.objects是一个django.db.models.manager.Manager对象,而Manager类中的方法,全都来自于QuerySet类,以下介绍QuerySet上的一些常用的API。

返回新的QuerySet

 使用QuerySetAPI进行数据筛选时,方法返回的仍是一个QuerySet对象,依此可以对API进行链式调用,对数据进行多层筛选。
比如筛选完后还要根据某个字段进行排序,则可以通过链式调用进行:

articles = Article.objects.filter(author__name="abc").order_by("publish_time")

 以下介绍返回新的QuerySet对象的方法:

  1. filter:将满足条件的数据筛选出来,返回新的QuerySet对象;

  2. exclude:排除满足条件的数据,返回一个QuerySet对象;

  3. annotate:给QuerySet中的每个对象都添加一个使用查询表达式(聚合函数、F表达式、Q表达式)的新字段,返回一个操作后的QuerySet对象;示例代码:

    articles = Article.objects.annotate(author_name=F("author__name"))
    
  4. order_by:将查询结果根据某个字段从小到大排序,若要倒叙排序,则可以在传入字段前加入一个负号。需注意的是,对于多个order_by的链式调用,会将前面排序的顺序打乱;

  5. values:将指定的字段数据提取出来,以"字段名":"字段值"的键值对存储到字典中。默认情况下会将表中所有的字段全部都提取出来,也可以传入字段名字符串进行指定。此时的QuerySet结果集中的元素不再是模型,而是字典。

    articles = Article.objects.values("title","content")
    for article in articles:
    	print(article)
    

    以上article的打印结果是类似于{"title":"abc","content":"abc"}的形式。

  6. values_list:类似于values,只不过返回的QuertSet中,存储的不是多个字典,而是一个元素为("字段值1","字段值2",...)的列表。如果该元组中只有一个字段,则可以传递参数flat=True将数据扁平化,此时结果为QuerySet的结果为["数据1","数据2",...]

  7. all:获取ORM模型的QuerySet对象,即获取表中的所有数据。

  8. 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在取数据前调用。

  9. 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对象
    
  10. defer:过滤掉表中不需要的字段,提高查询的效率,此时若调用在返回的模型实例上访问该字段,则会重新向数据库中进行一次查找操作。注意defer不能过滤id字段。
    示例代码:

    articles = Article.objects.defer("title")
    for article in articles:
    	print(article.title)	#此时将重新向数据库进行一次查找操作
    
  11. only:与defer类似,只不过defer时过滤掉指定字段,而only是只提取指定字段。onlyvalues的区别是返回的QuerySet对象中存储的是模型实例,而valuesQuerySet中存储的是字典。

  12. get:获取一条数据,该方法要求待筛选的数据在数据库中有且仅有一条。

  13. create:创建一条数据,保存到数据库中。该方法相当于先用指定的模型创建一个对象,然后再调用该对象的.save()方法。
    示例代码:

    article = Article.objects.create(title='abc')	
    
  14. get_or_create:根据某个条件进行查找,如果找到了则返回这条数据,如果没有找到则创建这条数据。

  15. bulk_create:传入一个模型实例列表,一次性创建多个数据。
    示例代码:

    Article.objects.bulk_create([
    	Article(title="abc"),
    	Article(title="bcd"),
    ])
    
  16. count:获取提取的数据的个数。如果想要知道总共有多少条数据,则建议使用count,而非len(articles)。因为count在底层是使用select count(*)实现的,该方式比将所有数据从数据库中提取出来后再使用len函数更加高效。

  17. firstlast:返回QuerySet中的第一条或最后一条数据。

  18. aggregate:使用聚合函数

  19. exists:判断某个条件的数据是否存在。如果要判断符合某条件的数据是否存在,则建议使用exists,该法比使用count或直接判断QuerySet是否为空更有效。

  20. distinct:去除掉重复的数据。

  21. update :数据更新操作。

  22. delete:删除所有满足条件的数据。

  23. 切片操作:在QuerySet对象上也可进行切片操作。且在数据选择时的切片操作并不是把所有数据从数据库中提取出来再做切片操作,而是在数据库层面使用LIMIEOFFSET来帮完成。

什么时候会执行SQL语句

  生成一个QuerySet对象并不会马上转换为并不会马上转换为SQL语句取执行,只有在以下情况下QuerySet才会转换为SQL执行:

  1. 迭代:在遍历QuerySet对象时,会先执行这个SQL语句,然后再将结果返回进行迭代。
    for article in Articles.objects.all():
    	print(article.title)
    
  2. 使用步长的切片操作:对QuerySet对象做切片操作本身不会执行SQL语句,但是若在切片操作时提供了步长,则会立马执行SQL语句。即切片操作的结果是QuerySet对象,带步长的切片操作返回实际的数据。需注意的是,带步长的切片操作后不能再使用查询操作。
  3. 调用len函数:调用len函数获取QuerySet中的数据数时也会执行SQL语句。
  4. 调用list函数:调用list函数将QuerySet对象转换为列表对象也会立马执行SQL语句。
  5. 判断:若对某个QuerySet进行判断,会立即执行SQL语句。

即创建QuerySet对象时不会马上执行SQl语句,从QuerySet对象中获取具体的信息时才会执行SQL。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值