django—ORM相关

常用的QuerySet方法

  1、all()

    查询表中所有数据,返回一个QuerySet对象列表

  2、filter()

    查询满足条件的数据,返回一个QuerySet对象列表

  3、get()

    查询指定的数据(存在且唯一的数据)

    查询不到则报错,查询到多条数据也报错

  4、order_by("字段")

    将查询到的对象列表按照字段排序,默认是升序

    "-字段"为降序

    多字段排序order_by("字段1", "字段2")

      优先按照字段1排序,字段1相等的数据再按照字段排序

  5、reverse()

    对已经排好序的对象列表进行翻转(用在order_by后面)

  6、values()

    将对象列表转换为字典列表

    即[对象1,对象2...]《=============》[{对象1对应的数据字典},{对象2对应的数据字典}...]

    传入指定参数,可以指定字典中只存放指定的字段和值

  7、values_list()

    将对象列表转换为元组列表

    即[对象1,对象2...]《=============》[(对象1对应的所有数据的值),(对象2对应的所有数据的值)...]

    传入指定参数,可以指定元组中只存放指定字段的值

  8、distinct()

    去重,查询结果有重复值时去重

    如果是:

        id=1,name=a,age=18

        id=2,name=a,age=18

    则不会去重,因为这两条数据的id不同

    distinct不能传入指定参数去重

    只能够通过查询方法,查询指定字段的数据后将重复值去重

  9、count()

    计数,统计数据的个数

    效果和len()一样

    效率高于len(),推荐QuerySet使用count计数

  10、first()

    获取对象列表中的第一个对象

  11、last()

    获取对象列表中的最后一个对象

  12、exists()

    判断对象列表是否为空,布尔值

  13、exclude()

    获取不满足条件的对象列表

    与filter作用相反

 

单表的双下划线操作

  在对QuerySet做条件查询的时候,使用双下滑操作可以实现一些逻辑的操作

  比如:

    需要查询id值大于某个值的所有数据时,django是不允许使用 filter(id>10)这种形式的,这就需要用到双下划线操作

  1、小于某一个值(less than)

    字段名__lt = 10             <=====>    字段值<10

  2、大于(greater than)

    字段名__gt = 10          <=====>    字段值>10

  3、小于等于(less than equal)

    字段名__lte = 10          <=====>    字段值<=10

  4、大于等于(greater than equal)

    字段名__gte = 10          <=====>    字段值>=10

  5、大于等于  且  小于等于

    字段名__range = [1,10]            <=====>    1<=字段值<=10 

    range表示取一定区间内的值,左右均能取到(和python语法中的range不同,这里的10是可以取到的)

  6、成员判断

    字段名__in = [1,2,3,4,5]

    这里的列表和 5 中的列表不同,5中的列表只接受两个值,表示一个区间范围

    这里的列表可以存放多个值,条件判断的结果是满足成员判断的结果(即查询出来的结果只能是出现在列表中的)

  7、字符串包含匹配

    a、区分大小写

      字段名__contains = "test"

      匹配结果的改字段中必须包含test,如test01、01test、01test01均可被匹配到

    b、不区分大小写  ( i表示ignore )

      字段名__icontains = "test"

      匹配结果的改字段中可以包含test或者TEST,如Test01、01TeSt、01test01均可被匹配到

  8、字符串匹配以指定字符开头或者结尾

    a、区分大小写

      字段名__startwith = "xxx"

      字段名__endwith = "xxx"

    b、不区分大小写

    字段名__istartwith = "xxx"

    字段名__iendwith = "xxx"

   9、对于日期类型的字段匹配

    字段__year = "2020"      获取2020年的所有数据

    字段__month = "1"   获取1月份的所有数据(查询结果可能为空,即使有相关数据)

    字段__day = "1"   获取1日的所有数据(查询结果可能为空,即使有相关数据)

    还可以用字符串方式匹配:

      字段__contains = "2020-1-1"   获取2020年1月1日的数据

      字段__contains = "-1-"  获取1月份的数据

  10、获取指定字段为空的数据

    字段__isnull = True

    注意:空字符串并不是null,null是初始化时为空

    

外键相关查询操作

  这里,简单举个1对多的关系:班级(1)和学生(多)的关系

  此时创建表时,外键字段(cls)自然就设置在学生表中

  1、基于对象的查询

    a、正向查询(通过外键字段进行的查询,即1:n关系中n的那一方的对象查询1的那一方的对象)

      通过一个学生对象,要想获取对应的班级信息:

      student_obj.cls,即可获取到对应的班级对象

    b、反向查询(通过对方的类名小写的方式查询,即1:n关系中1的那一方的对象查询n的那一方的对象。此时己方表中并没有对方的相关字段)

      通过一个班级对象,要想获取对应的学生信息:

      cls_obj.students_set,即可获取一个关系管理对象(反向查询的一个媒介,set就是集合的意思)

      cls_obj.students_set.all(),即可获取到当前班级对象对应的所有学生对象(返回一个对象列表)

    

    补充:关系管理对象的名称可以修改(如果不想使用  类名小写_set的形式获取关系管理对象)

      在定义外键字段的时候,可以加上参数related_name = "",指定一个名称方便后续获取关系管理对象

      设置related_name以后,就无法通过  类名小写_set 形式获取关系管理对象了

  2、基于字段的查询

    a、正向查询

      根据外键字段信息查询

      如需要查询所有班级名称为1的学生:

      models.Students.objects.filter(cls__name="1")       这实际上是根据一个跨表查询的数据,来完成当前表的数据筛选

      另外一种方式:

      先查询一个名称为1的班级对象       cls_obj = models.Cls.objects.filter(name="1")

      再查询1班的所有学生                     models.Students.objects.filter(cls = cls_obj)

    b、反向查询

      通过学生名查询对应班级信息(此时班级表中没有学生的相关字段)  

      没有在外键指定 related_name时:

        models.Cls.objects.filter(students__name="test"),此时只能通过类名小写形式进行双下划线跨表操作

      在外键指定了related_name时:

        models.Cls.objects.filter(这里换成指定的名称__name="test")       指定了related_name就只能用它查询,否则报错

      如果觉得related_name在查询时使用不方便:

        还以在外键中设置related_query_name指定一个查询时专用的名称,该名称只能用于查询字段时使用

        同时设置了related_name、related_query_name在字段查询时只能用后者,获取关系管理对象时只能用前者

 

多对多关系的查询操作

  多对多关系需要创建第三张表

  在django模型类的定义中,提供了一个便利操作,无需定义第三个类

  只需要在N:N关系的其中一方的模型类中定义一个ManytoMany字段即可,to参数可以是一个类名,也可以是类名的字符串形式(反射机制可以通过字符串拿到对应的类),ManytoMany字段和外键不同,它没有级联操作(delete on cascade等,更新数据需要在逻辑业务中实现)

  例如,书籍与作者的关系(n:n),假设ManytoMany字段定义在作者表中(book)

  1、基于对象的查询  

    a、通过作者对象获取对应的的书籍信息(正向查询,因为ManytoMany字段在作者表中)

      author_obj.book,此时获取到的依然是一个关系管理对象(与外键操作不同,外键操作中N的那一方直接通过外键字段获取到另一方的数据对象,是因为另一方是唯一确定的,而多对多关系中,双方获取对方信息的个数是不确定的)

    b、通过书籍对象获取对应的作者信息(方向查询,查询方式和外键操作中一致)

      book_obj.authors_set,作者类名_set的形式获取到关系管理对象,此时同样可以在ManytoMany字段中设置related_name修改关系管理对象的名称

  2、基于字段的查询

    和外键查询操作如出一辙

    同样可以设置ManytoMany字段中的related_query_name来修改字段查询的名称

  3、通过一个作者对象设置作者和书籍之间的对应关系

    author_obj.book,获取关系管理对象

    author_obj.book.set([ ])通过关系管理对象下的set方法,传入一个列表,列表中可以是多个书籍的的id或者书籍对象

    完成设置,即可将关系表中的对应关系修改完成

 

关系管理对象的方法

  1、all方法    获取该关系管理对象下的所有对象信息

  2、set方法   设置多对多关系(或者1对多关系)

    设置多对多关系时

      set方法接收的列表,可以是多个id值,也可以是多个对象

    设置1对多关系时,

      set方法接收的列表,只能是对象列表

  3、add方法  添加多对多关系(或者1对多关系)

    往关系表中新增数据,add方法接收可变长的位置参数,即add(*args)形式

    添加多对多关系时

      可以传入的是id,或者是对象

    添加1对多关系时

      只能传入对象

  4、remove  删除多对多关系(或者1对多关系)

    同样接收一个可变长的位置参数

    注:删除1对多关系时,需要将外键指定设置为null=True否则无法删除

  5、clear   清空关系表

    不接收任何参数

    注:清空1对多关系时,同样需要将外键指定设置为null=True否则无法清空

  6、create 新增一个对象,且和当前对象建立关系

    author_obj.books.create(name="测试")

    新增一本书《测试》存入书籍表,并且与当前作者建立关系,存入关系表中

 

聚合和分组

  1、django常用的内置聚合函数:

    form django.db.models import Max, Min, Count, Sum, Avg

    Max:最大值

    Min:最小值

    Count:计数

    Sum:求和

    Avg:求平均值

  对于QuerySet执行聚合操作需要用到聚合方法aggregate(),在聚合方法内使用相应的聚合函数即可

    对象列表.aggregate(Max("指定字段"))             求某个字段的最大值

    返回结果是一个字典:{"指定字段名__max": 对于的值},键名是由字段名  + 双下划线 + 相应聚合函数的小写组成

    如果想要指定字典中键的名称,可以将方法内函数写成关键字形式,如:对象列表.aggregate(max=Max("指定字段")),这样就指定了键的名称为max

  aggregate也称为终止子句,因为该方法返回的结果不再是QuerySet,因此后续无法再进行相关查询操作。

  

  2、分组(group by)

    分组使用到的方法:annotate

    统计每本书的作者个数:

    models.Book.objects.annotate(Count("authors"))

    models.Book.objects:表示按书进行分组

    Count("authors"):统计分组后每本书的作者个数,因为多对多字段定义在作者类中,所以Count指定的字段为作者表的小写(或者related_name如果指定了该属性的话)

    annotate:负责将统计的结果,作为属性值插入到每本书的对象中,然后返回一个对象列表

    

  annotate实现了分组的过程

    实际上将分组聚合后的结果添加到了每个分组的对象上

 

F查询和Q查询

  from django.db.models  import F,Q

  1、F查询

    获取比较同一张表中不同字段的结果

    F("字段"):获取当前对象中指定字段的值

    如获取书籍表中,库存大于销量的书

      models.Book.objects.filter(库存__gt=F("销量"))

      对应的sql:select book_name from books where 库存>销量

  

  2、Q查询,进行与(&)或(|)非(~)操作

    如获取id值大于5或者小于3的数据

    models.Book.objects.filter(Q(id__gt=5)| Q(id__lt=3))

 

事务

  from django.db import transaction

  执行事务:

    with transaction.atomic():

      # with内部执行一系列操作(要么都执行,要么都不执行)

  

  执行事务过程中 ,中途报错的话会触发回滚机制,之前的操作全部撤销

  为了不影响代码正常运行,需要进行异常捕获

  注意:异常捕获必须在with外部 ,也就是将整个with子句包括起来,才能正常执行事务

     如果在with内部进行异常捕获的,既然异常能够正确被处理,却无法触发回滚机制,异常发生前的所有操作不会被撤销。

 

posted @ 2020-07-10 17:46  yamx  阅读(211)  评论(0编辑  收藏  举报