目录
一 聚合查询
1. 级联
级联删除
级联更新
2. 聚合函数
使用 aggregate
使用场景
3. 分组查询
语法
使用 annotate
代码
4. F 与 Q 查询
F 查询
Q 查询
二 ORM 字段及参数
1.ORM 字段
常用字段
不常用字段
字段合集
2. 关系字段
ForeignKey(): 外键字段
OneToOneField(): 一对一外键字段
ManyToManyField(): 多对多关系字段
3. 字段属性
- null
- unique
- db_index
- default
4. 自定义字段类型
三 断开关联的关系表
1. 断开外键关联的 ForeignKey 使用
2. 断开关联的多对多自动创建关系表
3. 断开关联的多对多手动创建关系表
总结
图书管理系统
RBAC 基于角色的权限管理
ORM 中的事务操作
什么是事务
四大特性
数据库的三大范式(设计范式)
第一范式(1NF)
第二范式(2NF)
第三范式(3NF)
django 开启事务
导入
开启
回滚
一 聚合查询
1. 级联
级联删除
操作外键字段管理数据的时候
书跟出版社是一对多关系, 外键字段在书那, 如果把出版社删了, 所对应的书也会自动删除
级联更新
如果把出版社主键值改变, 那么书籍表中的出版社主键值也会更新改变
2. 聚合函数
聚合函数必须用在分组之后
没有分组其实默认整体就是一组
Max Min Sum Sum Avg Count
使用 aggregate
关键字 aggregate
还需要导入模块
from django.db.models import Max,Min,Sum,Sum,Avg,Count
只要跟数据库相关的功能, 基本上都在 django.db.models 里面
如果不在, 可能直接在 django.db 中
使用场景
单独使用: 不分组, 只聚合结果(aggregate)
分组使用: 按字段分组, 可分组字段与聚合结果(annotate)
1. 筛选出价格最高的书籍的
- res = models.Book.objects.aggregate(mr = Max('price'))
- print(res)
2. 求书籍总价格
- res = models.Book.objects.aggregate(sm = Sum('price'))
- print(res)
3. 求书籍平均价格
- res = models.Book.objects.aggregate(av = Avg('price'))
- print(res)
4. 一起使用
- res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('price'),Avg('price'))
- print(res)
3. 分组查询
语法
values('分组字段').annotate(别名 = 聚合函数('字段')).filter(聚合字段别名条件).values('取分组字段', '取聚合字段别名')
什么时候需要分组
统计每一个部门的平局薪资
统计每一个部门的男女比例
统计某一数据的组别内数据
使用 annotate
关键字 annotate
借助于聚合函数
from django.db.models import Max,Min,Sum,Sum,Avg,Count
django 中 models 后面点什么, 就按什么分组
代码
1. 统计每一本书的作者个数 书名 和对应的作者人数
- res = models.Book.objects.annotate(author_num=Count('authors__id')).values('title','author_num')
- print(res)
2. 统计出每个出版社卖的最便宜的书的价格 出版社的名字 价格
- res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
- print(res)
按照其他字段分组
- res = models.Publish.objects.values('想要分组的字段名').annotate(min_price=Min('book__price')).values('name','min_price')
- print(res)
3. 统计不止一个作者的图书
1. 先拿书及对应的作者数
2. 再筛选出大于一的图书 书名 作者数目
- res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num')
- print(res)
4. 查询各个作者出的书的总价格 作者名字 总价格
- res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
- print(res)
4. F 与 Q 查询
F 查询
通过字段名获取可以直接做运算的查询结果
F 基于 F('字段条件')
导入
from django.db.models import F
使用
后面的条件是来自于数据库的其他字段值
更改字符数操作, 需要借助于 Concat 方法, 在后面拼接字符串
from django.db.models import F,Q
1. 查询库存数大于卖出数的书籍
- res = models.Book.objects.filter(kun_cun__gt = F('mai_cun')).values('title') # 后面的条件是来自于数据库的其他字段值
- print(res)
2. 将所有书的价格上涨 100 块
models.Book.objects.all().update(price=F('price') + 100)
3. 将所有书的名称后面全部加上 "爆款" 后缀 了解知识点 操作字符串数据需要借助于 Concat 方法
- from django.db.models.functions import Concat
- from django.db.models import Value
- ret3 = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
Q 查询
完成逻辑运算方式的查询
Q 基于 Q('字段条件')
三种运算符
&(与) |(或) ~(非)
导入
from django.db.models import Q
使用
1. 查询一下书籍名称是三国演义 或者 库存数是 500 的书籍
- res = models.Book.objects.filter(title='三国演义',kun_cun=500) # and 关系
- res = models.Book.objects.filter(title='三国演义',kun_cun=500) # and 关系
- res = models.Book.objects.filter(Q(title='三国演义'),Q(kun_cun=500)) # Q 包裹之后逗号还是 and 关系
- res = models.Book.objects.filter(Q(title='三国演义') | Q(kun_cun=500)) # | 就是 or 的关系
- res = models.Book.objects.filter(~Q(title='三国演义') | Q(kun_cun=500)) # ~ 就是 not 关系
- print(res)
Q 对象高级用法
q.children(('元组'))
按条件查询时, 可以传字符串进行查询默认是 and 关系, 更改 connector 改为 or, 对象前加~ 取反
- q = Q()
- q.connector = 'or' # 默认是 and 可以改成 or
- q.children.append(('title','三国演义'))
- q.children.append(('kun_cun__gt',500))
- res = models.Book.objects.filter(~q) # 取反
- print(res)
二 ORM 字段及参数
1.ORM 字段
常用字段
字段 | 说明 | 字段属性 |
---|---|---|
AutoField() | 默认自增主键 (primary_key=True),django 会默认建立 id 字段主键 | |
CharField() | 字符类型 | max_length=64,数据长度,必须明确 |
IntegerField() | 整型 | |
DateField() | 年月日时间类型 | -- auto_now=True,数据被更新就会更新时间 < br ztid="289" ow="0" oh="0">-- auto_now_add=True,数据第一次参数时产生 |
DateTimeField() | 年月日小时分钟秒时间类型 | -- auto_now=True,数据被更新就会更新时间 < br ztid="294" ow="0" oh="0">-- auto_now_add=True,数据第一次参数时产生 |
DecimalField() | 混合精度的小数类型 | -- max_digits=3,限定数字的最大位数 (包含小数位) -- decimal_places=2,限制小数的最大位数 |
BooleanField() | 布尔字段,对应数据库 tinyint 类型 数据长度只有 1 位 | 内部只接收 0/1 或者 True/Flase |
TextField | 专门用来存大段文本 | |
FileField | 专门用来文件路径 | upload_to = ‘/etc/data‘, 给该字段传值的时候 直接传文件对象 |
- CharField varchar
- IntegerField int
- BigIntegerField bigint
- EmailField varchar(254)
- DateField
- DateTimeField
auto_now: 每次修改数据的时候 都会自动将当前修改时间更新上去 实时更新
auto_now_add: 在创建数据的时候 会将当前时间自动记录 之后不会自动修改 除非你人为修改
AutoField auto_increment
BooleanField 布尔值
该字段在存储的时候 你只需要传布尔值 True 或 False
它会自动存成 1/0
TextField 专门用来存大段文本
FileField 专门用来文件路径 '/etc/data/a.txt'
upload_to = '/etc/data'
给该字段传值的时候 直接传文件对象
会自动将文件对象保存到 upload_to 后面指定的文件路径中
然后将路径保存到数据库
DecimalField(Field)
- 10 进制小数
- 参数:
max_digits, 小数总长度
decimal_places, 小数位长度
DateField 和 DateTimeField
auto_now_add
配置 auto_now_add=True, 创建数据记录的时候会把当前时间添加到数据库.
auto_now
配置上 auto_now=True, 每次更新数据记录的时候会更新该字段.
不常用字段
- # 1. BigAutoField(): 大整型自增
- # 2. BigIntegerField(): 长整型
- # 3. EmailField(): 邮箱字段, 拥有 / admin / 验证
- # 4. FloatField(): 浮点型小数
- # 5. SmallIntegerField(): 小整型
- # 6. TextField(): 大文本类型
- # 7. FileField(): 文件字段
字段合集
AutoField(Field)
- int 自增列, 必须填入参数 primary_key=True
BigAutoField(AutoField)
- bigint 自增列, 必须填入参数 primary_key=True
注: 当 model 中如果没有自增列, 则自动会创建一个列名为 id 的列
- from django.db import models
- class UserInfo(models.Model):
- # 自动创建一个列名为 id 的且为自增的整数列
- username = models.CharField(max_length=32)
- class Group(models.Model):
- # 自定义自增列
- nid = models.AutoField(primary_key=True)
- name = models.CharField(max_length=32)
- SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field)
- 布尔值类型
NullBooleanField(Field):
- 可以为空的布尔值
CharField(Field)
- 字符类型
- 必须提供 max_length 参数, max_length 表示字符长度
TextField(Field)
- 文本类型
EmailField(CharField):
- 字符串类型, Django Admin 以及 ModelForm 中提供验证机制
IPAddressField(Field)
- 字符串类型, Django Admin 以及 ModelForm 中提供验证 IPV4 机制
GenericIPAddressField(Field)
- 字符串类型, Django Admin 以及 ModelForm 中提供验证 Ipv4 和 Ipv6
- 参数:
protocol, 用于指定 Ipv4 或 Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为 True, 则输入::ffff:192.0.2.1 时候, 可解析为 192.0.2.1, 开启此功能, 需要 protocol="both"
URLField(CharField)
- 字符串类型, Django Admin 以及 ModelForm 中提供验证 URL
SlugField(CharField)
- 字符串类型, Django Admin 以及 ModelForm 中提供验证支持 字母, 数字, 下划线, 连接符(减号)
CommaSeparatedIntegerField(CharField)
- 字符串类型, 格式必须为逗号分割的数字
UUIDField(Field)
- 字符串类型, Django Admin 以及 ModelForm 中提供对 UUID 格式的验证
FilePathField(Field)
- 字符串, Django Admin 以及 ModelForm 中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field)
- 字符串, 路径保存在数据库, 文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件, 默认 django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串, 路径保存在数据库, 文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件, 默认 django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DateTimeField(DateField)
- 日期 + 时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 长整数, 时间间隔, 数据库中按照 bigint 存储, ORM 中获取的值为 datetime.timedelta 类型
FloatField(Field)
- 浮点型
DecimalField(Field)
- 10 进制小数
- 参数:
max_digits, 小数总长度
decimal_places, 小数位长度
BinaryField(Field)
- 二进制类型
字段合集
ORM 字段与 MySQL 字段对应关系
对应关系:
- 'AutoField': 'integer AUTO_INCREMENT',
- 'BigAutoField': 'bigint AUTO_INCREMENT',
- 'BinaryField': 'longblob',
- 'BooleanField': 'bool',
- 'CharField': 'varchar(%(max_length)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
- 'DateField': 'date',
- 'DateTimeField': 'datetime',
- 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
- 'DurationField': 'bigint',
- 'FileField': 'varchar(%(max_length)s)',
- 'FilePathField': 'varchar(%(max_length)s)',
- 'FloatField': 'double precision',
- 'IntegerField': 'integer',
- 'BigIntegerField': 'bigint',
- 'IPAddressField': 'char(15)',
- 'GenericIPAddressField': 'char(39)',
- 'NullBooleanField': 'bool',
- 'OneToOneField': 'integer',
- 'PositiveIntegerField': 'integer UNSIGNED',
- 'PositiveSmallIntegerField': 'smallint UNSIGNED',
- 'SlugField': 'varchar(%(max_length)s)',
- 'SmallIntegerField': 'smallint',
- 'TextField': 'longtext',
- 'TimeField': 'time',
- 'UUIDField': 'char(32)',
ORM 字段与 MySQL 字段对应关系
2. 关系字段
ForeignKey(): 外键字段
外键类型在 ORM 中用来表示外键关联关系, 一般把 ForeignKey 字段设置在 '一对多'中'多'的一方.
ForeignKey 可以和其他表做关联关系同时也可以和自身做关联关系.
字段参数
to
设置要关联的表
to_field
设置要关联的表的字段
on_delete
当删除关联表中的数据时, 当前表与其关联的行的行为.
models.CASCADE
删除关联数据, 与之关联也删除
db_constraint
是否在数据库中创建外键约束, 默认为 True.
- # 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")
OneToOneField(): 一对一外键字段
一对一字段.
通常一对一字段用来扩展已有字段.(通俗的说就是一个人的所有信息不是放在一张表里面的, 简单的信息一张表, 隐私的信息另一张表, 之间通过一对一外键关联)
字段参数
to
设置要关联的表.
to_field
设置要关联的字段.
on_delete
当删除关联表中的数据时, 当前表与其关联的行的行为.(参考上面的例子)
- #2,OneToOneField(): 一对一外键字段
- # -- 字段同外键
ManyToManyField(): 多对多关系字段
- #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()
3. 字段属性
null
用于表示某个字段可以为空
- #1. null: 默认为 False,True 表示字段可为 null, 与数据库相关
- a1 = models.CharField(max_length=20) # 插入数据时该字段必须赋值
- a2 = models.CharField(max_length=20, null=True) # 插入数据时可以为空
- unique
如果设置为 unique=True 则该字段在此表中必须是唯一的
db_index
如果 db_index=True 则代表着为此字段设置索引.
default
为该字段设置默认值.
- #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, 该字段值不可重复
4. 自定义字段类型
- class MyCharField(model.Field):
- def __init__(self,max_length,*args,**kwargs):
重新调用父类的方法
super().__init__(max_length=max_length,*args,**kwargs)
调用创建库字段时的类型方法
- def db_type(self,connection):
- return'char(%s)' % self.max_length
三 断开关联的关系表
1. 断开外键关联的 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)
2. 断开关联的多对多自动创建关系表
- # 使用 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)
3. 断开关联的多对多手动创建关系表
手动创建关系表的好处: 手动创建关系表可以让关系表可以拥有更多的自身的字段, 同时通过关系表类名可以直接获取第三张表
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(因为关系表拥有自己的字段, 这些方法无法直接操作这些字段)
图书管理系统
待完成
RBAC 基于角色的权限管理
在 Web 领域中, url 就是一切
ORM 中的事务操作
什么是事务
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务.
事务处理可以用来维护数据库的完整性, 保证成批的 SQL 语句要么全部执行, 要么全部不执行.
事务用来管理 insert,update,delete 语句
客户 A 要给客户 B 转一笔钱, 这个在数据库中需要进行两步:
1. 客户 A 减钱
2. 客户 B 加钱
如果在第一步结束后, 服务器出现异常, 停下了, 第二步没有进行, 如果数据库使用了事务操作, 真的出现异常的时候, 前面的操作会进行回滚.
简单的说就是: 要么全部执行成功, 要么一个都不执行
这个回滚的操作就叫做数据库的原子性操作.
四大特性
ACID
原子性
事务是最小的单位, 不可再分
一致性
事务要求所有的 DML 语句操作时, 必须保证同时成功或者同时失败
隔离性
事务与事务之间是隔离的
持久性
是事务的保证, 事务终结的标志(内存的数据持久到硬盘)
数据库的三大范式(设计范式)
第一范式(1NF)
表中的列只能含有原子性 (不可再分) 的值
第二范式(2NF)
满足第一范式
没有部分依赖
表必须有一个主键
没有包含在主键中的列必须完全依赖于主键, 而不能只依赖主键的一部分.
第三范式(3NF)
满足第二范式
没有传递依赖
即每个属性都跟主键有直接关系而不是间接关系
django 开启事务
导入
from django.db import transaction
开启
with transaction.atomic()
在缩进的代码中书写数据库操作
该缩进的所有代码, 都是一个事务
pass
回滚
rollback()
回滚就是回到上一个状态
来源: http://www.bubuko.com/infodetail-3307925.html