[笔记] Model 层 QuerySet 的使用

Model 层 QuerySet 的使用

    • 常用的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是否有数据,返回TrueFalse
    • bulk_create 接口,同create,用来批量创建记录
    • in_bulk 接口,批量查询,接收两个参数 id_listfield_name
    • update 接口,根据条件批量更新记录
    • delete 接口,同update,根据条件批量删除记录
    • values 接口,当我们只需要返回某个字段的值,不需要Model实例时,可以使用,用法:title_list = Post.objects.filter(category_id=1).values('title')
    • values_list 接口,同values,直接返回包含tupleQuerySet

进阶接口

  • 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()
  • QQ表达式就是用来解决 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用来直接计算结果
除了CountSum外,还有AvgMinMax等表达式,均用来满足我们对SQL查询的需求

你可能感兴趣的:(python后台开发学习,笔记)