Django之集合函数使用与mysql表的创建特殊字段分析

1. 集合函数的使用场景:

  -- 单独使用: 不分组, 只查聚合结果

  -- 分组使用: 按字段分组, 可查询分组字段与聚合结果

2. 导入聚合函数

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

3. 单独聚合查询: aggregate

# 语法:
aggregate(别名=聚合函数('字段'))

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

# 案例:所有书中最贵的书的价格
Book.objects.all().aggregate(high_price=Max('price'))
# 不分组单独使用的聚合函数 aggregate  把整个大表看成一个组
#high_price 这个是自定义的别名 方便后期调用

4. 分组聚合查询: annotate

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

# 规则:
1.values(...).annotate(...)为分组组合,values控制分组字段,annotate控制聚合字段
2.values可按多个字段分组values('分组字段1', ..., '分组字段n'),??如果省略代表按操作表的主键分组
3.可以同时对多个字段进行聚合处理annotate(别名1=聚合函数1('字段1'), ..., 别名n=聚合函数n('字段n'))
4.分组后的的filter代表having判断,只对聚合字段进行条件判断,可以省略(对非聚合字段或分组字段进行条件判断代表where判断)
5.取字段值values(...)省略默认取所有分组字段与聚合字段,也可以自主取个别分组字段及聚合字段(取字段的values中出现了非分组或非聚合字段,该字段自动成为分组字段)

# 案例:每个出版社出版的最贵的书的价格高于50元的出版社名与最高价格
Book.objects.all().values('publish__name').annotate(high_price=Max('price')).filter(high_price__gt=50).values('publish__name', 'high_price')
# 案例:每个出版社出版的最贵的书的价格高于50元的出版社名与最高价格
res = Book.objects.values('publish__name')
    .annotate(high_price=Max('price'))
    .filter(high_price__gt=50)
    .values('publish__name', 'high_price')
print(res)

#注意 'publish__name' 这个就是分组的字段
# 注意 high_price=Max('price')  就是自定义别名
# 注意 filter(high_price__gt=50) 就是分组后的过滤条件, 等于mysql中的having 函数
# 注意 values('publish__name', 'high_price')  最后取值 一定取分组字段与自定义别名


res = Publish.objects.values('name')
    .annotate(high_price=Max('book__price'))
    .filter(high_price__gt=50)
    .values('name', 'high_price')
print(res)

mysql表的创建常用字段属性解析

'''
1. null:默认为False,True表示字段可为null
2. blank:默认为False,True表示字段可为空
3. choice:可选的,限制了该选项的字段值必须是所指定的choice中的一个:
    -- sex = models.SmallIntegerField(choices=((1, '男'), (2, "女")))
    -- obj.get_sex_display()
4. db_column:自定义字段名
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类型
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. ForeignKey():外键字段
    -- 字段属性to关联模型类
    -- 字段属性to_field关联字段,省略默认关联主键
    -- 字段属性on_delete (外键关联数据被删除时的操作)
        -- models.CASCADE 级联删除
        -- modles.PROTECT 抛出异常
        -- models.SET_NULL 设置空值
        -- models.SET_DEFAULT 设置默认值
        -- models.SET(value)自定义值
    -- 字段属性related_name自定义反向查询的字段名
    -- 字段属性db_constraint=False取消关联关系,但还可以使用连表查询
总结:models.ForeignKey(to='关联的类名', null=True, on_delete=models.SET_NULL, db_constraint=False, related_name="本类名小写")

2、OneToOneField():一对一外键字段
    -- 字段同外键
3、ManyToManyField():多对多关系字段
    -- 字段属性to关联模型类
    -- 字段属性through关联关系类
    -- 字段属性through_fields关联关系表中(本身类名小写字段, 关联表类名小写字段)
'''
关系字段-表与表关联的字段设置详解
# 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)
    
'''
一对多关系Foreignkey用法
# *****
# 使用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)
'''
断开关联关系的多对多自动建表

建表的案例:

from django.db import models

# Create your models here.

# Book书籍:id  name  price  publish_date  publish(publish_id)
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()
    # 在2.x环境下外键要明确on_delete字段属性
    publish = models.ForeignKey(to='Publish', to_field='id', on_delete=models.CASCADE)
    author = models.ManyToManyField(to='Author')

# 给你Book与Author

# Author作者:id  name
class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    author_detail = models.OneToOneField(to='AuthorDetail', to_field='id', on_delete=models.CASCADE)


# AuthorDetail作者详情: id  age  telephone  info
class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    age = models.IntegerField()
    telephone = models.BigIntegerField()
    info = models.TextField()


# Publish出版社:id  name  address
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    address = models.CharField(max_length=64)



class UserInfo(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    age = models.IntegerField()
    gender = models.SmallIntegerField()
    province = models.CharField(max_length=20)
    city = models.CharField(max_length=20)


class Test1(models.Model):
    a1 = models.CharField(max_length=20)  # 插入数据时该字段必须赋值
    a2 = models.CharField(max_length=20, null=True)  # 插入数据时可以为空

    # choices为元组套元组,子元组的第一个值类型要与字段类型对应,
    # 第二个值可以代表第一个值得特殊含义
    # 通过get_tagName_display()获取特殊含义
    choices = ((0, ''), (1, ''))
    sex = models.SmallIntegerField(choices=choices, default=0, db_column='gender')

    res = models.BooleanField(default=False)



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")
建表的案例模板分析

 基于orm的优化查询方案:

# only: 只取规定的字段形成对象(查主键)
# uq11 = Uesr.objects.all().only('name', 'age')
# print(uq11)
# print(uq11.query)
# print(uq11.first().name)
# print(uq11.first().gender)  # 自己又重新执行了查询该字段的sql
#
# defer:只取规定的字段外的字段形成对象(查主键)
# uq12 = Uesr.objects.all().defer('name', 'age')
# print(uq12)
# print(uq12.query)
#
# 好处:只对所需字段进行查询
# 坏处:数据放在字典中,相比对象取值不是那么方便
# uq2 = Uesr.objects.values('name', 'age')
# print(uq2)
# print(uq2.query)
优化查询有only 与defer两种方案
原文地址:https://www.cnblogs.com/gukai/p/10773278.html