zoukankan      html  css  js  c++  java
  • Djiango orm 单表查询

    一、分组查询

    1、概念

    # Book: id  name  price  publish_date  publish
    
    1. 聚合函数可以单独使用: 将整张表作为一个大的分组,查询字段只能是聚合结果
    select max(price), group_concat(name) from book where id < 10;
    
    2. 聚合函数在分组下使用
    select publish_id, max(price) as high_price from book group by publish_id having max(price) > 50

    2、使用场景

     1)聚合函数的使用场景:
        a、单独使用:不分组,只查聚合结果(aggregate);
        b、分组使用:按字段分组,可查分组字段与聚合结果 (annotate)。

     2)聚合函数使用前需要先进行导入:

    # 导入聚合函数
    from django.db.models import Avg, Max, Min, Count, Sum

    3、单独聚合查询 aggregate

     1)语法:

    aggregate(别名=聚合函数('字段'))

     2)规则:
      1.可以同时对多个字段进行聚合处理:aggregate(别名1=聚合函数1('字段1'), ..., 别名n=聚合函数n('字段n'));
      2.查询结果是QuerySet对象方法;
      3.方法返回值为dict类型。

     3)案例:

    # 案例:所有书中最贵的书的价格
    Book.objects.all().aggregate(high_price=Max('price'))
    print(dic)

    4、组聚合查询 annotate

     1)语法:

    values('分组字段').annotate(别名=聚合函数('字段')).filter(聚合字段别名条件).values('取分组字段', '取聚合字段别名')

     2)规则:

      1.values(...).annotate(...)为分组组合,values控制分组字段,annotate控制聚合字段;

    res = UserInfo.objects.values('province', 'city').annotate(high_age=Max('age'))

      2.values可按多个字段分组values('分组字段1', ..., '分组字段n'),取字段的values中出现了非分组或非聚合字段,该字段自动成为分组字段(这样会使分组变得无意义,因此取字段的values中不应出现非分组或非聚合字段);

    res = UserInfo.objects.values('province', 'city').annotate(high_age=Max('age')).values('city', 'high_age', 'name')
    # 取值values中出现name字段,django的orm在分组是为了避免出现报错会将‘name’字段加到第一个values中作为一个分组依据。
    
    res = UserInfo.objects.values('province', 'city').annotate(high_age=Max('age')).filter(city__contains="济南").values('city', 'high_age')
    print(res)

      3.可以同时对多个字段进行聚合处理annotate(别名1=聚合函数1('字段1'), ..., 别名n=聚合函数n('字段n'));
      4.分组后的的filter代表having判断,只对聚合字段进行条件判断,可以省略(对非聚合字段或分组字段进行条件判断代表where判断);

    # 案例:每个出版社出版的最贵的书的价格高于50元的出版社名与最高价格
    res = Book.objects.values('publish__name')
        .annotate(high_price=Max('price'))
        .filter(high_price__gt=50)
        .values('publish__name', 'high_price')
    print(res)
    #  filter中出现了聚合函数(annotate)中的参数时相当于sql查询语句中的having
    
    res = Publish.objects.values('name')
        .annotate(high_price=Max('book__price'))
        .filter(name__icontains='n')
        .values('name', 'high_price')
    print(res)
    #  filter中出现非聚合函数(annotate)中的参数时,django的orm会将其有优化为where条件放到分组前面进行过滤

      5.取字段值values(...)省略默认取所有分组字段与聚合字段,也可以自主取个别分组字段及聚合字段(取字段的values中出现了非分组或非聚合字段,该字段自动成为分组字段)。

    res = UserInfo.objects.values('province', 'city').annotate(high_age=Max('age'))
    
    res = UserInfo.objects.values('province', 'city').annotate(high_age=Max('age')).filter(city__contains="济南").values('province','city', 'high_age')
    
    # 上面两个查询语句所得到的查询结果相同
    print(res)

    二、常用共有字段属性

    #1. null:默认为False,True表示字段可为null,与数据库相关
        a1 = models.CharField(max_length=20)  # 插入数据时该字段必须赋值
        a2 = models.CharField(max_length=20, null=True)  # 插入数据时可以为空
    
    #2. blank:默认为False,True表示字段可为空, 与表单验证相关
    #3. choice:可选的,限制了该选项的字段值必须是所指定的choice中的一个:
        -- sex = models.SmallIntegerField(choices=((1, ''), (2, "")))
        -- obj.get_sex_display()
    
    #4. db_column:自定义字段名
    sex = models.SmallIntegerField(choices=choices, default=0, db_column='gender')
    # 他只是将数据库中的字段变为gender,在django中若要查询该字段的值仍需要输入sex,因此不常用,不建议使用。
    
    #5. db_index:如果为True的话,设置索引
    #6. default:字段默认值
    #7. editable:默认为True,若为False,则不会在/admin/界面显示
    #8. primary_key:若设置为True,则表示将该字段设置为主键。一般情况下django默认会设置一个自增长的id主键。
    #9. unique:若设置为True,该字段值不可重复

    三、常用字段

    # 1. AutoField():默认自增主键(primary_key=True),django会默认建立id字段主键
    # 2. BooleanField():布尔字段,对应数据库tinyint类型  数据长度只有1位 内部只接收0/1或者True/Flase
    # 3. CharField():字符类型
        -- 字段属性max_length=64,数据长度,必须明确
    # 4. DateField():年月日时间类型
        -- 字段属性auto_now=True,数据被更新就会更新时间
        -- 字段属性auto_now_add=True,数据第一次参数时产生
    # 5. DateTimeField():年月日小时分钟秒时间类型
        -- 字段属性auto_now=True,数据被更新就会更新时间
        -- 字段属性auto_now_add=True,数据第一次参数时产生
    # 6. DecimalField():混合精度的小数类型
        -- 字段属性max_digits=3,限定数字的最大位数(包含小数位)
        -- 字段属性decimal_places=2,限制小数的最大位数
    # 7. IntegerField():整型

    四、不常用字段

    # 1. BigAutoField():大整型自增
    # 2. BigIntegerField():长整型
    # 3. EmailField():邮箱字段,拥有/admin/验证
    # 4. FloatField():浮点型小数
    # 5. SmallIntegerField():小整型
    # 6. TextField():大文本类型
    # 7. FileField():文件字段

    五、关系字段

    # 1. ForeignKey():外键字段
        #-- 字段属性to关联模型类
        #-- 字段属性to_field关联字段,省略默认关联主键
        #-- 字段属性on_delete (外键关联数据被删除时的操作)
            #-- models.CASCADE 级联删除
    class Book(models.Model):
         publish = models.ForeignKey(to='Publish', to_field='id', on_delete=models.CASCADE)
            #-- modles.PROTECT 抛出异常
            #-- models.SET_NULL 设置空值
            #-- models.SET_DEFAULT 设置默认值
            #-- models.SET(value)自定义值
        #-- 字段属性related_name自定义反向查询的字段名,自定义后方向查询自定义的名字会将默认的类名下划线set覆盖。
    
        #-- 字段属性db_constraint=False取消关联关系,但还可以使用连表查询
    #总结:models.ForeignKey(to='关联的类名', null=True, on_delete=models.SET_NULL, db_constraint=False, related_name="本类名小写")
    
    class Test2(models.Model):
        name = models.CharField(max_length=20)
        test1 = models.ForeignKey(to='Test1', null=True, on_delete=models.SET_NULL, db_constraint=False, related_name="tt")
    
    #2、OneToOneField():一对一外键字段
    #    -- 字段同外键
    #3、ManyToManyField():多对多关系字段
        #-- 字段属性to关联模型类
        #-- 字段属性through关联关系类
        #-- 字段属性through_fields关联关系表中(本身类名小写字段, 关联表类名小写字段)    
    class MyBook(models.Model):
           my_author = models.ManyToManyField(to='MyAuthor', through='MyBook_MyAuthor', through_fields=('mybook', 'myauthor'))
    
    class MyAuthor(models.Model):
        name = models.CharField(max_length=20)
    
    class MyBook_MyAuthor(models.Model):
        mybook = models.ForeignKey(to="MyBook", null=True, on_delete=models.SET_NULL, db_constraint=False)
        myauthor = models.ForeignKey(to='MyAuthor', null=True, on_delete=models.SET_NULL, db_constraint=False)
        time = models.DateField()

    六、断开外键关联的ForeignKey使用

    # 1、不使用ForeignKey方式断开关联(即建表的时候就不让其拥有自动关联关系,而是手动的靠创建数据时的数据录入建立关联关系),查询的时候不再支持Django ORM连表查询语法
    class Publish(models.Model):
        name = models.CharField(max_length=20)
    class Book(models.Model):
        name = models.CharField(max_length=20)
        # 字段需要写_id来表示相关表的字段信息
        publish_id = models.IntegerField()
    
    # *****
    # 2、使用ForeignKey方式用db_constraint=False字段属性断开关联,依然支持Django ORM连表查询语法,建议使用
    class Publish(models.Model):
        name = models.CharField(max_length=20)
    class Book(models.Model):
        name = models.CharField(max_length=20)
        # 字段不需要写_id来表示相关表的字段信息,ORM会自动添加
        publish = models.ForeignKey(to='Publish', null=True, on_delete=models.SET_NULL, db_constraint=False)

    七、断开关联的多对多自动创建关系表

    # 使用ManyToManyField方式用db_constraint=False字段属性断开关联,依然支持Django ORM连表查询语法,建议使用
    class MyBook(models.Model):
        name = models.CharField(max_length=20)
        my_author = models.ManyToManyField(to='MyAuthor', db_constraint=False)
    class MyAuthor(models.Model):
        name = models.CharField(max_length=20)

    八、断开关联的多对多手动创建关系表

      手动创建关系表的好处:手动创建关系表可以让关系表可以拥有更多的自身的字段,同时通过关系表类名可以直接获取第三张表

      1、和自动建立关系表类似,依然支持Django ORM连表查询语法(多对多借助关系表连表查询)

    class Book(models.Model):
        name = models.CharField(max_length=20)
        
    class Author(models.Model):
        name = models.CharField(max_length=20)
        
    class Book_Author(models.Model):
        book = models.ForeignKey(to="Book", null=True, on_delete=models.SET_NULL, db_constraint=False)
        author = models.ForeignKey(to='Author', null=True, on_delete=models.SET_NULL, db_constraint=False)
        time = models.DateField()

      2、手动创建关系表,在关系表中用ForeignKey方式支持基于外键关系表的ORM连表查询,同时明确ManyToManyField字段,所以也支持ORM正向方向连表查询
           -- db_constraint=False断开关联可以在ForeignKey或ManyToManyField任意一方完成

    class Book(models.Model):
        name = models.CharField(max_length=20)
        # 明确through与through_fields,ManyToManyField才不会自动建立关系表
        author = models.ManyToManyField(to='Author', through='Book_Author')
        
    class Author(models.Model):
        name = models.CharField(max_length=20)
        
    class Book_Author(models.Model):
        book = models.ForeignKey(to="Book", null=True, on_delete=models.SET_NULL, db_constraint=False)
        author = models.ForeignKey(to='Author', null=True, on_delete=models.SET_NULL, db_constraint=False)
        time = models.DateField()

      总结:手动创建第三张表,第三张表的增删改就采用关系表类名衍生的create|delete|update,就不再拥有add|clear|remove|set(因为关系表拥有自己的字段,这些方法无法直接操作这些字段)

  • 相关阅读:
    随机出题问题
    简读《构建之法》提问
    大二下第一次课后作业
    大道至简第七第八章读后感
    继承与接口动手动脑
    大道至简第六章读后感
    数组里的随机数问题
    大道至简第五章读后感
    输入法的用户界面
    搜索水王
  • 原文地址:https://www.cnblogs.com/peng-zhao/p/10491972.html
Copyright © 2011-2022 走看看