[内容] MariaDB & MySQL 事务

内容目录:

内容一:事务的作用

内容二:MariaDB & MySQL 事务的 4 大特性
2.1 原子性(Atomicity)
2.2 一致性(Consistency)
2.3 隔离性(Isolation)
2.4 持久性(Durability)

内容三:MariaDB & MySQL 事务隔离级别
3.1 MariaDB & MySQL 事务隔离级别的特点
3.2 MariaDB & MySQL 默认的事务隔离级别
3.3 查看目前所使用的事务隔离的方法

具体的内容:

内容一:事务的作用

事务的作用是保护数据的安全性

内容二:MariaDB & MySQL 事务的 4 大特性
2.1 原子性(Atomicity)

一系列操作被看作一个事务,这个事务里面的所有操作要么全部失败,要么全部成功,如果在操作的过程中出现中断,则立刻进行 rollback

2.2 一致性(Consistency)

一系列操作被看作一个事务,在事务开始前和结束后,整个库的完整逻辑约束不能被打破,例如:一个人向另一个人转账,不能出现一个人转账成功另一个人没有收到转账,或者一个人转账失败另一个人收到转账的情况

2.3 隔离性(Isolation)

主要解决并发的情况,避免不同的人,在相同的时间,查看到的数据的不一致性,避免以下情况的发生:
1) 脏读:一个事务读取了另一个事务更新、提交并撤销的数据,导致此事务看到的数据是错误的
2) 不可重复读:一个事务多次读取了另一个事务多次更新并提交的数据,导致此事务看到的数据是来回变化的
3) 幻读:一个事务在批量修改所有数据,但是在修改的过程中另一个事务又往里面插入了数据,导致此事务在修改完成之后,意外发现还有一条数据没有修改

2.4 持久性(Durability)

事务结束后,所有更新都将被保存,不能回滚

内容三:MariaDB & MySQL 事务隔离级别
3.1 MariaDB & MySQL 事务隔离级别的特点

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

3.2 MariaDB & MySQL 默认的事务隔离级别

可重复读 repeatable-read

3.3 查看目前所使用的事务隔离的方法

MariaDB [(none)]> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.001 sec)

(补充:这里以查看 MariaDB 目前所使用的事务隔离为例)

[实验] Django 最大值、最小值、平均值等特殊数值的数据查询

注意:

本实验是接着 《Django 自定义逻辑添加(通过自定义 save 对象实现)(一次性完成多对多表数据的插入)》而继续的

正文:

步骤目录:

步骤一:进入相应的 Django 环境

步骤二:插入测试数据

步骤三:设置一个显示上一句 SQL 语句的函数

步骤四:通过聚合函数查询所需的数值
4.1 通过聚合函数查询最大值
4.1.1 导入聚合函数最大值模块
4.1.2 通过聚合函数查询最大值(显示默认解释说明)
4.1.2.1 通过聚合函数查询最大值(显示默认解释说明)
4.1.2.2 显示通过聚合函数查询最大值的 SQL 语句(显示默认解释说明)
4.1.3 通过聚合函数查询最大值(显示自定义解释说明)
4.1.3.1 通过聚合函数查询最大值(显示自定义解释说明)
4.1.3.2 显示通过聚合函数查询最大值的 SQL 语句(显示自定义解释说明)
4.2 通过聚合函数查询最小值
4.2.1 导入聚合函数最小值模块
4.2.2 通过聚合函数查询最小值
4.2.3 显示通过聚合函数查询最小值的 SQL 语句
4.3 通过聚合函数统计数据条数
4.3.1 导入聚合函数统计数据条数的模块
4.3.2 通过聚合函数统计数据条数(统计所有数据的条数)
4.3.2.1 通过聚合函数统计数据条数(统计所有数据的条数)
4.3.2.2 显示通过聚合函数统计数据条数的 SQL 语句(统计所有数据的条数)
4.3.3 通过聚合函数统计数据条数(统计某一字段数据的条数)
4.3.3.1 通过聚合函数统计数据条数(统计某一字段数据的条数)
4.3.3.2 显示通过聚合函数统计数据条数的 SQL 语句(统计某一字段数据的条数)
4.4 通过聚合函数求和
4.4.1 导入聚合函数求和的模块
4.4.2 通过聚合函数求和
4.4.3 显示通过聚合函数求和的 SQL 语句
4.5 通过聚合函数求平均数
4.5.1 导入聚合函数求平均数的模块
4.5.2 通过聚合函数求平均值
4.5.3 显示通过聚合函数求平均值的 SQL 语句

步骤五:通过分组聚合函数查询所需的数值
5.1 导入分组聚合函数模块
5.2 通过分组聚合函数统计每组数据的条数
5.2.1 通过分组聚合函数统计每组数据的条数
5.2.2 显示通过分组聚合函数统计每组数据条数的 SQL 语句
5.3 通过分组聚合函数统计求每组数据的平均值
5.3.1 通过分组聚合函数统计求每组数据的平均值
5.3.2 显示通过分组聚合函数统计求每组数据的平均值的 SQL 语句

步骤六:通过子查询查询所需的数值
6.1 导入子查询模块
6.2 通过子查询查询总值最大的一组数据的总值
6.2.1 通过子查询查询总值最大的一组数据的总值
6.2.2 显示通过子查询查询总值最大的一组数据总值的 SQL 语句

步骤七:通过关联查询查询所需的数值
7.1 导入关联查询模块
7.2 通过关联查询查询关联的数据
7.2.1 通过关联查询查询关联的数据(查询数据表中的非外键字段)
7.2.1.1 通过关联查询查询关联的数据(查询数据表中的非外键字段)
7.2.1.2 通过关联查询查询关联数据的 SQL 语句(查询数据表中的非外键字段)
7.2.2 通过关联查询查询关联的数据(查询数据表中的外键字段)
7.2.2.1 通过关联查询查询关联的数据(查询数据表中的外键字段)
7.2.2.2 通过关联查询查询关联数据的 SQL 语句(查询数据表中的外键字段)

步骤八:退出相应的 Django 环境

步骤九:Django 聚合函数查询、分组聚合函数查询、子查询、关联查询的总结

具体的操作步骤:

正文:

步骤一:进入相应的 Django 环境

(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from user.models import *

步骤二:插入测试数据

>>> user = Student(sname='zhangsan',score=60,cls=Clazz(cname='Class1'))
>>> user.save()

>>> user = Student(sname='lisi',score=80,cls=Clazz(cname='Class1'))
>>> user.save()

>>> user = Student(sname='wangwu',score=90,cls=Clazz(cname='Class1'))
>>> user.save()

>>> user = Student(sname='zhaoliu',score=70,cls=Clazz(cname='Class1'))
>>> user.save()

>>> user = Student(sname='xueer',score=70,cls=Clazz(cname='Class2'))
>>> user.save()

>>> user = Student(sname='huangyi',score=70,cls=Clazz(cname='Class2'))
>>> user.save()

(补充:这里以随机插入 6 条测试数据为例)

步骤三:设置一个显示上一句 SQL 语句的函数

>>> def showsql():
...     from django.db import connection
...     print(connection.queries[-1]['sql'])

(补充:这里的 [-1] 是指显示上一条操作的 SQL 语句)

步骤四:通过聚合函数查询所需的数值
4.1 通过聚合函数查询最大值
4.1.1 导入聚合函数最大值模块

>>> from django.db.models import Max

4.1.2 通过聚合函数查询最大值(显示默认解释说明)
4.1.2.1 通过聚合函数查询最大值(显示默认解释说明)

>>> Student.objects.aggregate(Max('score'))
{'score__max': 90}


补充:
1) 这里以查询所有数据 score 字段的最大值为例
2) 这里查出的最大值是 90

4.1.2.2 显示通过聚合函数查询最大值的 SQL 语句(显示默认解释说明)

>>> showsql()
SELECT MAX(`user_student`.`score`) AS `score__max` FROM `user_student`

(补充:这里以查询所有数据 score 字段的最大值为例)

4.1.3 通过聚合函数查询最大值(显示自定义解释说明)
4.1.3.1 通过聚合函数查询最大值(显示自定义解释说明)

>>> Student.objects.aggregate(m=Max('score'))
{'m': 90}


补充:
1) 这里以查询所有数据 score 字段的最大值为例
2) 查出的最大值是 90
3) 这里显示的自定义解释说明是 m

4.1.3.2 显示通过聚合函数查询最大值的 SQL 语句(显示自定义解释说明)

>>> showsql()
SELECT MAX(`user_student`.`score`) AS `m` FROM `user_student`


补充:
1) 这里以查询所有数据 score 字段的最大值为例
2) 这里显示的自定义解释说明是 m

4.2 通过聚合函数查询最小值
4.2.1 导入聚合函数最小值模块

>>> from django.db.models import Min

4.2.2 通过聚合函数查询最小值

>>> Student.objects.aggregate(Min('score'))
{'score__min': 60}


补充:
1) 这里以查询所有数据 score 字段的最小值为例
2) 这里查出的最小值是 60

4.2.3 显示通过聚合函数查询最小值的 SQL 语句

>>> showsql()
SELECT MIN(`user_student`.`score`) AS `score__min` FROM `user_student`

(补充:这里以查询所有数据 score 字段的最小值为例)

4.3 通过聚合函数统计数据条数
4.3.1 导入聚合函数统计数据条数的模块

>>> from django.db.models import *

4.3.2 通过聚合函数统计数据条数(统计所有数据的条数)
4.3.2.1 通过聚合函数统计数据条数(统计所有数据的条数)

>>> Student.objects.aggregate(c=Count('*'))
{'c': 6}


补充:
1) 这里统计所有数据的数据总条数为例
2) 这里显示的自定义解释说明是 c
3) 这里查出的数据条数是 6

4.3.2.2 显示通过聚合函数统计数据条数的 SQL 语句(统计所有数据的条数)

>>> showsql()
SELECT COUNT(*) AS `c` FROM `user_student`


补充:
1) 这里统计所有数据的数据总条数为例
2) 这里显示的自定义解释说明是 c

4.3.3 通过聚合函数统计数据条数(统计某一字段数据的条数)
4.3.3.1 通过聚合函数统计数据条数(统计某一字段数据的条数)

>>> Student.objects.aggregate(c=Count('score'))
{'c': 6}


补充:
1) 这里以统计包含 score 字段的数据总条数为例
2) 这里显示的自定义解释说明是 c
3) 这里查出的数据条数是 6

4.3.3.2 显示通过聚合函数统计数据条数的 SQL 语句(统计某一字段数据的条数)

>>> showsql()
SELECT COUNT(`user_student`.`score`) AS `c` FROM `user_student`


补充:
1) 这里以统计包含 score 字段的数据总条数为例
2) 这里显示的自定义解释说明是 c

4.4 通过聚合函数求和
4.4.1 导入聚合函数求和的模块

>>> from django.db.models import *

4.4.2 通过聚合函数求和

>>> Student.objects.aggregate(Sum('score'))
{'score__sum': 440}


补充:
1) 这里以求所有数据 score 字段的值的和为例
2) 这里求出的和是 440

4.4.3 显示通过聚合函数求和的 SQL 语句

>>> showsql()
SELECT SUM(`user_student`.`score`) AS `score__sum` FROM `user_student`

(补充:这里以求所有数据 score 字段的值的和为例)

4.5 通过聚合函数求平均数
4.5.1 导入聚合函数求平均数的模块

>>> from django.db.models import *

4.5.2 通过聚合函数求平均值

>>> Student.objects.aggregate(Avg('score'))
{'score__avg': 73.3333}


补充:
1) 这里以求所有数据 score 字段的平均值为例
2) 这里求出的平均值是 73.3333

4.5.3 显示通过聚合函数求平均值的 SQL 语句

>>> showsql()
SELECT AVG(`user_student`.`score`) AS `score__avg` FROM `user_student`

(补充:这里以求所有数据 score 字段的平均值为例)

步骤五:通过分组聚合函数查询所需的数值
5.1 导入分组聚合函数模块

>>> from django.db.models import *

5.2 通过分组聚合函数统计每组数据的条数
5.2.1 通过分组聚合函数统计每组数据的条数

>>> Student.objects.values('cls').annotate(c=Count('score'))
<QuerySet [{'cls': 1, 'c': 4}, {'cls': 2, 'c': 2}]>


补充:
1) 这里以 cls 字段进行分组,统计每组包含 score 字段数据的条数为例
2) 这里显示的自定义解释说明是 c
3) 这里求出 cls 字段值为 1 的组包含 score 字段的数据有 4 条,cls 字段的值为 2 的组包含 score 字段的数据有 2 条

5.2.2 显示通过分组聚合函数统计每组数据条数的 SQL 语句

>>> showsql()
SELECT `user_student`.`cls_id`, COUNT(`user_student`.`score`) AS `c` FROM `user_student` GROUP BY `user_student`.`cls_id` ORDER BY NULL LIMIT 21


补充:
1) 这里以 cls 字段进行分组,统计每组包含 score 字段数据的条数为例
2) 这里显示的自定义解释说明是 c

5.3 通过分组聚合函数统计求每组数据的平均值
5.3.1 通过分组聚合函数统计求每组数据的平均值

>>> Student.objects.values('cls').annotate(a=Avg('score'))
<QuerySet [{'cls': 1, 'a': 75.0}, {'cls': 2, 'a': 70.0}]>


补充:
1) 这里以 cls 字段进行分组,求每组数据 score 字段的平均值为例
2) 这里显示的自定义解释说明是 a
3) 这里求出 cls 字段值为 1 的组 score 字段的平均值为 75.0,cls 字段的值为 2 的组 score 字段的平均值为 70.0

5.3.2 显示通过分组聚合函数统计求每组数据的平均值的 SQL 语句

>>> showsql()
SELECT `user_student`.`cls_id`, AVG(`user_student`.`score`) AS `a` FROM `user_student` GROUP BY `user_student`.`cls_id` ORDER BY NULL LIMIT 21


补充:
1) 这里以 cls 字段进行分组,求每组数据 score 字段的平均值为例
2) 这里显示的自定义解释说明是 a

步骤六:通过子查询查询所需的数值
6.1 导入子查询模块

>>> from django.db.models import *

6.2 通过子查询查询总值最大的一组数据的总值
6.2.1 通过子查询查询总值最大的一组数据的总值

>>> Student.objects.values('cls').annotate(s=Sum('score')).aggregate(m=Max('s'))
{'m': 300}


补充:
1) 这里以 cls 字段进行分组,求每组数据 score 字段的总值,再将其求和为例
2) 这里显示的自定义解释说明是 m
3) 这里求出 score 字段的总值为 300
4) values 和 annotate 一起使用时 values 则发挥的是 group by 的作用
5) values 单独使用时 values 发挥的是部分查询的作用

6.2.2 显示通过子查询查询总值最大的一组数据总值的 SQL 语句

>>> showsql()
SELECT MAX(`s`) FROM (SELECT `user_student`.`cls_id` AS Col1, SUM(`user_student`.`score`) AS `s` FROM `user_student` GROUP BY `user_student`.`cls_id` ORDER BY NULL) subquery


补充:
1) 这里以 cls 字段进行分组,求每组数据 score 字段的总值,再将其求和为例
2) 这里显示的自定义解释说明是 m
3) values 和 annotate 一起使用时 values 则发挥的是 group by 的作用
4) values 单独使用时 values 发挥的是部分查询的作用

步骤七:通过关联查询查询所需的数值
7.1 导入关联查询模块

>>> from django.db.models import *

7.2 通过关联查询查询关联的数据
7.2.1 通过关联查询查询关联的数据(查询数据表中的非外键字段)
7.2.1.1 通过关联查询查询关联的数据(查询数据表中的非外键字段)

>>> Student.objects.values('cls__cname')
<QuerySet [{'cls__cname': 'Class1'}, {'cls__cname': 'Class1'}, {'cls__cname': 'Class1'}, {'cls__cname': 'Class1'}, {'cls__cname': 'Class2'}, {'cls__cname': 'Class2'}]>


补充:
1) 这里查出了 4 条 cls__cname 为 Class1 的数据和 2 条 cls__cname 为 Class 2 的数据
2) 这里的 cls 是 Django 数据模型类中两张数据表的外键字段,但是 cname 并不是数据库中两张数据表的外键字段

7.2.1.2 通过关联查询查询关联数据的 SQL 语句(查询数据表中的非外键字段)

>>> showsql()
SELECT `user_clazz`.`cname` FROM `user_student` INNER JOIN `user_clazz` ON (`user_student`.`cls_id` = `user_clazz`.`id`) LIMIT 21

(补充:这里的 cls_id 是 user_student 表中关联 user_clazz 表中 id 字段的外键字段)

7.2.2 通过关联查询查询关联的数据(查询数据表中的外键字段)
7.2.2.1 通过关联查询查询关联的数据(查询数据表中的外键字段)

>>> Student.objects.values('cls__id')
<QuerySet [{'cls__id': 1}, {'cls__id': 1}, {'cls__id': 1}, {'cls__id': 1}, {'cls__id': 2}, {'cls__id': 2}]>


补充:
1) 这里查出了 4 条 cls__id 为 1 的数据和 2 条 cls__id 为 2 的数据
2) 这里的 cls 是 Django 数据模型类中两张数据表的外键字段,并且 id 也是数据库中两张数据表的外键字段

7.2.2.2 通过关联查询查询关联数据的 SQL 语句(查询数据表中的外键字段)

>>> showsql()
SELECT `user_student`.`cls_id` FROM `user_student` LIMIT 21

(补充:这里的 cls_id 是 user_student 表中关联 user_clazz 表中 id 字段的外键字段)

步骤八:退出相应的 Django 环境

>>> quit()

步骤九:Django 聚合函数查询、分组聚合函数查询、子查询、关联查询的总结

1) 单独用 aggregate 则代表单独使用聚合函数
2) 单独用 annotate 则代表单独使用分组聚合函数
3) 在 annotate 前面加上 values 则是指定某一个字段进行分组,values.annotate

[实验] Django 自定义逻辑添加 (通过自定义 save 对象实现) (一次性完成多对多表数据的插入)

注意:

文中的 python 系统名、mysite 项目、user 应用 Clazz 类和 Student 类只是站主在本次操作中随意取的名称,读者可以根据自己的喜好换成任意别的名称

正文:

步骤目录:

步骤一:系统环境要求

步骤二:安装 Django
2.1 安装 Python3
2.2 创建并进入 Django 项目的目录
2.3 将 Django 项目的目录指定为 Django 环境
2.4 进入 Django 环境

步骤三:创建 mysite 项目
3.1 创建 mysite 项目
3.2 mysite 项目的目录
3.2.1 安装 tree 目录显示软件
3.2.2 显示 mysite 项目的目录
3.2.3 Django 项目目录介绍

步骤四:创建 user 应用
4.1 创建 user 应用
4.2 user 应用的目录
4.2.1 显示 user 应用的目录
4.2.2 Django 应用目录介绍
4.3 在 mysite 应用中导入 user 应用

步骤五:实现 user 应用的层级多链接

步骤六:实现连接 MariaDB 数据库
6.1 安装 MairaDB 数据库和客户端
6.2 创建用于 Django 的 MairaDB 的库和用户
6.2.1 进入 MairaDB 数据库
6.2.2 创建用于 Django 的库
6.2.3 创建用于 Django 的用户
6.2.4 刷新权限
6.3 退出 MariaDB 数据库
6.4 重启 MariaDB

步骤七:搭建用于 Django 的 MariaDB 数据库环境
7.1 安装 Django 连接 MariaDB 的模块
7.2 在 mysite 应用中添加 Django 连接 MariaDB 的模块
7.3 在 user 应用数据库模板中添加 Clazz 类、Student 类和插入多对多数据的函数
7.4 在 mysite 应用中设置连接到 MariaDB 数据库
7.5 生成牵引文件
7.6 将牵引文件导入 MariaDB 数据库

步骤八:一次性完成多对多表数据的插入
8.1 进入相应的 Django 环境
8.2 一次性完成多对多表数据的插入
8.3 退出相应的 Django 环境

具体的操作步骤:

步骤一:系统环境要求

1) 服务器的系统需要是 openSUSE 15.2 版本
2) 服务器要关闭防火墙
3) 服务器系统要配置好可用的软件源(最好是软件数量最多的官方版本)
4) 服务器要能够连接外网

步骤二:安装 Django
2.1 安装 Python3

[root@python ~]# zypper -n install python3

2.2 创建并进入 Django 项目的目录

[root@python ~]# mkdir project
[root@python ~]# cd project

2.3 将 Django 项目的目录指定为 Django 环境

[root@python project]# python3 -m venv django_env

2.4 进入 Django 环境

[root@python project]# source django_env/bin/activate
(django_env) [root@python project]# pip install django

(补充:在此次操作发生时,最新的 Django 版本是 3.2)

步骤三:创建 mysite 项目
3.1 创建 mysite 项目

(django_env) [root@python project]# django-admin startproject mysite

3.2 mysite 项目的目录
3.2.1 安装 tree 目录显示软件

(django_env) [root@python project]# zypper -n install tree

3.2.2 显示 mysite 项目的目录

(django_env) [root@python project]# cd mysite
(django_env) [root@python mysite]# tree
.
├── manage.py
└── mysite
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

1 directory, 5 files

3.2.3 Django 项目目录介绍

1) mysite 此 Django 项目的容器
2) manage.py 命令行工具,与 Django 项目进行交互
3) mysite/__init__.py 空文件,通知 Python 此项目是一个 Python 包
4) mysite/settings.py 此 Django 项目的配置文件
5) mysite/urls.py 此 Django 项目的 URL 声明和 Django 的网站“目录”
6) mysite/wsgi.py WSGI 兼容 Web 服务器的入口

步骤四:创建 user 应用
4.1 创建 user 应用

(django_env) [root@python mysite]# django-admin startapp user

4.2 user 应用的目录
4.2.1 显示 user 应用的目录

(django_env) [root@python mysite]# tree
.
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── user
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

3 directories, 13 files

4.2.2 Django 应用目录介绍

1) user/app.py 此 Django 应用的容器
2) user/__init__.py 空文件,通知 python 此项目是一个 python 包
3) user/admin.py 此 Django 应用自带的后台管理相关的类
4) user/app.py 此 Django 应用指定应用名的文件
5) user/migrations.py 此 Django 应用通过 python 代码生成数据库表时里面会产生一些迁移文件
6) user/models.py 可以在里面创建一些 Python 对象并通过这些对象在数据库里创建对应的表
7) user/test.py 此 Django 应用的测试文档
8) user/views.py 此 Django 应用的视图,接收前端数据,把数据传递给后端,响应相关页面

4.3 在 mysite 应用中导入 user 应用

在 mysite/mysite/settings.py 中添加以下内容:

......
INSTALLED_APPS = [
......
    'user',
]
......

步骤五:实现 user 应用的层级多链接

创建 mysite/user/urls.py 并添加以下内容:

......
from django.conf.urls import url, include
......
mysite.mysite.urls.py
......
urlpatterns = [
......
    url(r'^register/', include('user.urls')),
]

(补充:这里以设置 /register/ 链接对应 user 应用的链接为例)

步骤六:实现连接 MariaDB 数据库
6.1 安装 MairaDB 数据库和客户端

(django_env) [root@python mysite]# zypper -n install mariadb mariadb-devel mariadb-server mariadb-client

6.2 创建用于 Django 的 MairaDB 的库和用户
6.2.1 进入 MairaDB 数据库

(django_env) [root@python mysite]# mysql -h 127.0.0.1 -p

6.2.2 创建用于 Django 的库

MariaDB [(none)]> create database user;

(补充:这里以创建 user 库为例)

6.2.3 创建用于 Django 的用户

MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;

(补充:这里以创建 root 用户,密码是 password 为例)

6.2.4 刷新权限

MariaDB [(none)]> flush privileges;

6.3 退出 MariaDB 数据库

MariaDB [(none)]> exit

6.4 重启 MariaDB

(django_env) [root@python mysite]# systemctl restart mariadb

步骤七:搭建用于 Django 的 MariaDB 数据库环境
7.1 安装 Django 连接 MariaDB 的模块

(django_env) [root@python mysite]# pip3 install hexdump
(django_env) [root@python mysite]# pip3 install pymysql

7.2 在 mysite 应用中添加 Django 连接 MariaDB 的模块

在 mysite/mysite/init.py 中添加以下内容:

import pymysql
pymysql.install_as_MySQLdb()

7.3 在 user 应用数据库模板中添加 Clazz 类、Student 类和插入多对多数据的函数

在 mysite/user/models.py 中添加以下内容:

......
class Clazz(models.Model):
    cname = models.CharField(max_length=30)

class Student(models.Model):
    sname = models.CharField(max_length=30)
    score = models.PositiveBigIntegerField()
    cls = models.ForeignKey(Clazz,on_delete=models.CASCADE)

    def __str__(self):
        return u'Student:%s,%s'%(self.sname,self.score)

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        try:
            self.cls = Clazz.objects.get(cname=self.cls.cname)
        except Clazz.DoesNotExist:
            self.cls = Clazz.objects.create(cname=self.cls.cname)

        #Insertion of student table
        models.Model.save(self, force_insert=False, force_update=False,using=None, update_fields=None)


补充:
1) models.ForeignKey(Clazz,on_delete=models.CASCADE) 会生成一个属于 Clazz 表的 id,user_class 表中会生成一个 cls_id 字段,这个字段是 Clazz 表中的 id 字段的外键
2) 这里以创建一次性完成多对多表数据的插入的 save 对象为例

7.4 在 mysite 应用中设置连接到 MariaDB 数据库

将 mysite/mysite/settings.py 中的以下内容:

......
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
......

修改为:

......
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'user',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': 'password',
    }
}
......


补充:这里以
1) 使用的库是 user
2) 使用的服务器是 127.0.0.1
3) 使用的端口是 3306
4) 使用的用户是 root
5) 使用的密码是 password
为例

7.5 生成牵引文件

(django_env) [root@python mysite]# python3 manage.py makemigrations
Migrations for 'user':
  user/migrations/0001_initial.py
    - Create model Clazz
    - Create model Student

7.6 将牵引文件导入 MariaDB 数据库

(django_env) [root@python mysite]# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, user
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK
  Applying user.0001_initial... OK

步骤八:一次性完成多对多表数据的插入
8.1 进入相应的 Django 环境

(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from user.models import *

8.2 一次性完成多对多表数据的插入

>>> user = Student(sname='zhangsan',score=60,cls=Clazz(cname='Class1'))
>>> user.save()

8.3 退出相应的 Django 环境

>>> quit()

公元后 1453 年 [事件] —— 君士坦丁堡的陷落,拜占庭帝国的灭亡

君士坦丁堡与拜占庭

在罗马帝国分裂成西罗马帝国和东罗马帝国即拜占庭帝国之后 (以下简称拜占庭帝国) ,拜占庭帝国一直位于基督教世界的最东边。

千百年以来,拜占庭帝国,是古希腊罗马文明的继承者,其首都君士坦丁堡是欧洲和西亚的贸易中枢,其本身同时也充当着基督教世界东部防线的角色,抵挡着波斯人、突厥人、阿拉伯人和土耳其人等民族的进攻。

基督教世界选择无视君士坦丁堡的陷落

在拥有如此众多关键角色的情况下,拜占庭一步步地被奥斯曼土耳其彻底征服。对于这一过程,整个基督教世界在进行了以保护之名行掠夺之实的臭名昭著的十字军东征运动之后,表现出了空前的冷漠。在军事上依赖拜占庭帝国作为屏障抵御奥斯曼土耳其的奥地利、波兰立陶宛联、俄罗斯,在宗教上和拜占庭相扶相依的天主教宗教中心梵蒂冈,在贸易上对拜占庭绝对依赖的欧洲贸易中心威尼斯都选择了无视拜占庭走向灭亡。

拜占庭最后的君士坦丁保卫战,在人类历史上留下了浓墨重彩的一笔。当奥斯曼土耳其的新式乌拉班大炮轰垮了君士坦丁堡曾无比坚固的城墙之时,拜占庭的贵族、工匠、作家、乞丐等和士兵们一同冲上去堵住缺口,拜占庭皇帝和臣民们之间也不再行君臣之礼,因为在死亡面前,人人平等。这似乎已不再是一场宗教主义、民族主义或国家主义的战争,而是人民们为了自己想要的生活方式而为自由意志战斗的战争。这是人类历史上,类似雅典公民们民主投票决定共同抵御波斯帝国入侵的又一个伟大的悲壮瞬间。

拜占庭帝国灭亡以后,基督教世界被彻底从西亚清除,伊斯兰教世界开始转入欧洲。

君士坦丁堡的世界职能开始被分担

君士坦丁堡陷落后,奥斯曼土耳其帝国只用了 50 年时间便开始围攻奥地利的首都维也纳,奥地利、匈牙利、波兰立陶宛联合王国和俄罗斯因为地理位置的关系被迫成为基督教世界新的前哨。

莫斯科承担了君士坦丁堡东正教中心的职责,转而与伊斯兰教进行对抗。

从亚洲而来的贸易线被奥斯曼帝国彻底切断,贸易中心威尼斯彻底衰落,欧洲赖以生存的香料价格猛涨了 70 多倍。急迫的贸易需求导致葡萄牙开始了探索新的海上贸易航线以取代过去拜占庭的功能。并以此带领世界走向了新的大航海时代。

拜占庭帝国即使灭亡之后,其精神依旧在这个世界激荡起伏

俄罗斯曾宣称自己是拜占庭帝国的继承者,声称这个世界是三个罗马的时代 (罗马帝国的时代、东罗马帝国 (拜占庭帝国) 的时代和俄罗斯的时代) ,并将自己的国徽改成和拜占庭一样的双头鹰。

希腊曾今想攻陷土耳其的首都伊斯坦布尔,并将名字改回成君士坦丁堡,将首度建立在那里,甚至连国家的名称都想改为叫做拜占庭。但是因为一系列对土耳其的军事失败才只好作罢。

拜占庭和罗马与雅典一样,已经成为了人历史中辉煌与伟大的代名词。

[实验] Django 自定义逻辑添加 (通过自定义 manager 管理器实现) (一次性完成多对多表数据的插入)

注意:

本实验是接着 《Django 数据展示(多对多版)》而继续的

正文:

步骤目录:

步骤一:在没有自定义 manager 管理器的情况下尝试一次性完成多对多表数据的插入
1.1 进入相应的 Django 环境
1.2 在没有自定义 manager 管理器的情况下尝试一次性完成多对多表数据的插入
1.3 退出相应的 Django 环境

步骤二:确认要插入的数据和预期的一致(可选)
2.1 创建一个自定义 manager 管理器的类
2.2 进入相应的 Django 环境
2.3 确认要插入的数据和预期的一致
2.4 退出相应的 Django 环境

步骤三:一次性完成多对多表数据的插入
3.1 创建一个自定义 manager 管理器的类
3.2 进入相应的 Django 环境
3.3 一次性完成多对多表数据的插入

具体的操作步骤:

步骤一:在没有自定义 manager 管理器的情况下尝试一次性完成多对多表数据的插入
1.1 进入相应的 Django 环境

>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from user.models import *

1.2 在没有自定义 manager 管理器的情况下尝试一次性完成多对多表数据的插入

>>> Student.objects.create(sname='lili',clazz='Class1',course=('Python','Shell'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/zhumingyu/Code/Django/mtwo/django_env/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/zhumingyu/Code/Django/mtwo/django_env/lib/python3.8/site-packages/django/db/models/query.py", line 451, in create
    obj = self.model(**kwargs)
  File "/Users/zhumingyu/Code/Django/mtwo/django_env/lib/python3.8/site-packages/django/db/models/base.py", line 503, in __init__
    raise TypeError("%s() got an unexpected keyword argument '%s'" % (cls.__name__, kwarg))
TypeError: Student() got an unexpected keyword argument 'clazz'


补充:
(1)这里数据插入失败
(2)按正常顺序应该是先插入班级 clazz,之后再插入学生 student,之后再插入课程 course,之后再去插入中间表

1.3 退出相应的 Django 环境

>>> quit();

步骤二:确认要插入的数据和预期的一致(可选)
2.1 创建一个自定义 manager 管理器的类

将 mysite/test/models.py 中的以下内容:

......
class Clazz(models.Model):
    cno = models.AutoField(primary_key=True)
    cname = models.CharField(max_length=30)

    def __str__(self):
        return u'Clazz:%s'%self.cname

class Course(models.Model):
    course_no = models.AutoField(primary_key=True)
    course_name = models.CharField(max_length=30)

    def __str__(self):
        return u'Course:%s'%self.course_name

class Student(models.Model):
    sno = models.AutoField(primary_key=True)
    sname = models.CharField(max_length=30)
    cls = models.ForeignKey(Clazz,on_delete=models.CASCADE)
    cour = models.ManyToManyField(Course)

    def __str__(self):
        return u'Student:%s'%self.sname

# Get class object according to class name
def getCls(cname):
    try:
        cls = Clazz.objects.get(cname=cname)
    except Clazz.DoesNotExist:
        cls = Clazz.objects.create(cname=cname)
    return cls

def getCourseList(*coursenames):
    courseList = []

    for cn in coursenames:
        try:
            c = Course.objects.get(course_name=cn)
        except Course.DoesNotExist:
            c = Course.objects.create(course_name=cn)
        courseList.append(c)

    return courseList

def registerStu(sname,cname,*coursenames):
    #1. Get class objects
    cls = getCls(cname)
    #2. Gets the list of course objects
    courseList = getCourseList(*coursenames)
    #3. Insert student table data
    try:
        stu = Student.objects.get(sname=sname)
    except Student.DoesNotExist:
        stu = Student.objects.create(sname=sname,cls=cls)
    #4. Insert intermediate table data
    stu.cour.add(*courseList)

    return True

修改为:

......
from django.db import models
from django.db.models.manager import Manager

# Create your models here.
class Clazz(models.Model):
    cno = models.AutoField(primary_key=True)
    cname = models.CharField(max_length=30)

    def __str__(self):
        return u'Clazz:%s'%self.cname

class Course(models.Model):
    course_no = models.AutoField(primary_key=True)
    course_name = models.CharField(max_length=30)

    def __str__(self):
        return u'Course:%s'%self.course_name

class CustomManager(Manager):
    def create(self, **kwargs):
        print(kwargs)

class Student(models.Model):
    sno = models.AutoField(primary_key=True)
    sname = models.CharField(max_length=30)
    cls = models.ForeignKey(Clazz,on_delete=models.CASCADE)
    cour = models.ManyToManyField(Course)

    objects = CustomManager()

    def __str__(self):
        return u'Student:%s'%self.sname

# Get class object according to class name
def getCls(cname):
    try:
        cls = Clazz.objects.get(cname=cname)
    except Clazz.DoesNotExist:
        cls = Clazz.objects.create(cname=cname)
    return cls

def getCourseList(*coursenames):
    courseList = []

    for cn in coursenames:
        try:
            c = Course.objects.get(course_name=cn)
        except Course.DoesNotExist:
            c = Course.objects.create(course_name=cn)
        courseList.append(c)

    return courseList

def registerStu(sname,cname,*coursenames):
    #1. Get class objects
    cls = getCls(cname)
    #2. Gets the list of course objects
    courseList = getCourseList(*coursenames)
    #3. Insert student table data
    try:
        stu = Student.objects.get(sname=sname)
    except Student.DoesNotExist:
        stu = Student.objects.create(sname=sname,cls=cls)
    #4. Insert intermediate table data
    stu.cour.add(*courseList)

    return True

(补充:这里以添加一个显示自己所有键值对的 CustomManager(Manager) 对象并在 Student 类中使用 objects 调用为例)

2.2 进入相应的 Django 环境

>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from user.models import *

2.3 确认要插入的数据和预期的一致

>>> Student.objects.create(sname='lili',clazz='Class1',course=('Python','Shell'))
{'sname': 'lili', 'clazz': 'Class1', 'course': ('Python', 'Shell')}

2.4 退出相应的 Django 环境

>>> quit();

步骤三:一次性完成多对多表数据的插入
3.1 创建一个自定义 manager 管理器的类

将 mysite/test/models.py 中的以下内容:

......
class Clazz(models.Model):
    cno = models.AutoField(primary_key=True)
    cname = models.CharField(max_length=30)

    def __str__(self):
        return u'Clazz:%s'%self.cname

class Course(models.Model):
    course_no = models.AutoField(primary_key=True)
    course_name = models.CharField(max_length=30)

    def __str__(self):
        return u'Course:%s'%self.course_name

class Student(models.Model):
    sno = models.AutoField(primary_key=True)
    sname = models.CharField(max_length=30)
    cls = models.ForeignKey(Clazz,on_delete=models.CASCADE)
    cour = models.ManyToManyField(Course)

    def __str__(self):
        return u'Student:%s'%self.sname

# Get class object according to class name
def getCls(cname):
    try:
        cls = Clazz.objects.get(cname=cname)
    except Clazz.DoesNotExist:
        cls = Clazz.objects.create(cname=cname)
    return cls

def getCourseList(*coursenames):
    courseList = []

    for cn in coursenames:
        try:
            c = Course.objects.get(course_name=cn)
        except Course.DoesNotExist:
            c = Course.objects.create(course_name=cn)
        courseList.append(c)

    return courseList

def registerStu(sname,cname,*coursenames):
    #1. Get class objects
    cls = getCls(cname)
    #2. Gets the list of course objects
    courseList = getCourseList(*coursenames)
    #3. Insert student table data
    try:
        stu = Student.objects.get(sname=sname)
    except Student.DoesNotExist:
        stu = Student.objects.create(sname=sname,cls=cls)
    #4. Insert intermediate table data
    stu.cour.add(*courseList)

    return True

修改为:

......
class Clazz(models.Model):
    cno = models.AutoField(primary_key=True)
    cname = models.CharField(max_length=30)

    def __str__(self):
        return u'Clazz:%s'%self.cname

class Course(models.Model):
    course_no = models.AutoField(primary_key=True)
    course_name = models.CharField(max_length=30)

    def __str__(self):
        return u'Course:%s'%self.course_name

class CustomManager(Manager):
    #Returns a class object
    def getClsObj(self,cname):
        try:
            cls = Clazz.objects.get(cname=cname)
        except Clazz.DoesNotExist:
            cls = Clazz.objects.create(cname=cname)
        return cls

    def getCourseList(self,*coursenames):
        cList = []
        for cn in coursenames:
            try:
                cour = Course.objects.get(course_name=cn)
            except Course.DoesNotExist:
                cour = Course.objects.create(course_name=cn)
            cList.append(cour)
        return cList

    def  create(self, **kwargs):
         clazz = kwargs.get('cls','')

         #Class information multi storage operation
         clas = self.getClsObj(clazz) 

         #Replace string with object
         #Student.objects.create(sname='',cls=clas)
         kwargs['cls'] = clas

         #Assign a separate value pair of course keys to course
         course = kwargs.pop('cour')

         #Storage operation of student information
         stu = Manager.create(self,**kwargs)

         #Total of the course information in storage
         courseList = self.getCourseList(*course)

         #The middle table of student course is stored in the database. An object or tuple can be unpacked automatically here
         stu.cour.add(*courseList)

class Student(models.Model):
    sno = models.AutoField(primary_key=True)
    sname = models.CharField(max_length=30)
    cls = models.ForeignKey(Clazz,on_delete=models.CASCADE)
    cour = models.ManyToManyField(Course)

    objects = CustomManager()

    def __str__(self):
        return u'Student:%s'%self.sname

# Get class object according to class name
def getCls(cname):
    try:
        cls = Clazz.objects.get(cname=cname)
    except Clazz.DoesNotExist:
        cls = Clazz.objects.create(cname=cname)
    return cls

def getCourseList(*coursenames):
    courseList = []

    for cn in coursenames:
        try:
            c = Course.objects.get(course_name=cn)
        except Course.DoesNotExist:
            c = Course.objects.create(course_name=cn)
        courseList.append(c)

    return courseList

def registerStu(sname,cname,*coursenames):
    #1. Get class objects
    cls = getCls(cname)
    #2. Gets the list of course objects
    courseList = getCourseList(*coursenames)
    #3. Insert student table data
    try:
        stu = Student.objects.get(sname=sname)
    except Student.DoesNotExist:
        stu = Student.objects.create(sname=sname,cls=cls)
    #4. Insert intermediate table data
    stu.cour.add(*courseList)

    return True

(补充:这里以创建一次性完成多对多表数据的插入的 manage 管理器为例)

3.2 进入相应的 Django 环境

(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from user.models import *

3.3 一次性完成多对多表数据的插入

>>> Student.objects.create(sname='lili',cls='Class4',cour=('CSS','JS'))


补充:这里
1) 第一步执行:objects = CustomManager()
2) 第二步执行:def create(self, **kwargs)
3) 第三步执行:clazz = kwargs.get(‘cls’,”),这步的结果是 clazz = ‘Class4’
4) 第四步执行:clas = self.getClsObj(clazz),这步的结果是如果 Class4 在数据库中不存在则插入此条数据,并让 clas = cls
5) 第五步执行:cours = kwargs.pop(‘cour’),这步的结果是 cours = (‘CSS’,’JS’)
6) 第六步执行:stu = Manager.create(self, **kwargs),这步的结果是 stu = Student.objects.create(sname=”,cls=clas)
7) 第七步执行:courseList = self.getCourseList(*course),这步的结果是如果 course 元组里的元素不存在则在数据库里创建,并将所有 course 里的元素放在 courseList 空列表中
8) 第八步执行:stu.cour.add(*courseList),这步的结果是将 courseList 里的元素插入 Student 类的 cour 字段对应的中间表里