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

时间:2023-03-09 13:32:45
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两种方案