[实验] 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()

[实验] 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 字段对应的中间表里

[内容] Python3 模块属性的查询

步骤一:进入 Python3 模式

# python3

步骤二:导入要显示所有属性的模块

>>> import types

(补充:这里以导入 types 模块为例)

步骤三:显示模块多所有属性

>>> dir(types)
['BooleanType',
 'BufferType',
 'BuiltinFunctionType',
 'BuiltinMethodType',
 'ClassType',
 'CodeType',
 'ComplexType',
 'DictProxyType',
 'DictType',
 'DictionaryType',
 'EllipsisType',
 'FileType',
 'FloatType',
 'FrameType',
 'FunctionType',
 'GeneratorType',
 'GetSetDescriptorType',
 'InstanceType',
 'IntType',
 'LambdaType',
 'ListType',
 'LongType',
 'MemberDescriptorType',
 'MethodType',
 'ModuleType',
 'NoneType',
 'NotImplementedType',
 'ObjectType',
 'SliceType',
 'StringType',
 'StringTypes',
 'TracebackType',
 'TupleType',
 'TypeType',
 'UnboundMethodType',
 'UnicodeType',
 'XRangeType',
 '__all__',
 '__builtins__',
 '__doc__',
 '__file__',
 '__name__',
 '__package__']

(补充:这里以显示 types 模块里的属性为例)

[实验] Django 自定义逻辑删除 (通过自定义 manager 管理器实现) (并非真的删除数据)

注意:

本实验是接着 《Django 通过自定义 manger 管理器进行自定义查询》而继续的

正文:

步骤目录:

步骤一:准备测试数据

步骤二:通过自定义 manager 管理器对某个数据进行单个的逻辑删除
2.1 创建一个自定义 manager 管理器的类
2.2 进入相应的 Django 环境
2.3 通过自定义 manager 管理器查询数据
2.4 通过自定义 manager 管理器逻辑删除第一条数据(将第一条数据的 isdelete=False 修改成 isdelete=True)
2.5 通过自定义 manager 管理器查询删除后的数据

步骤三:通过自定义 manager 管理器对一类数据进行批量的逻辑删除
3.1 创建一个自定义 manager 管理器的类
3.2 进入相应的 Django 环境
3.3 查看所有 isdelete=False 的数据
3.4 通过自定义 manager 管理器对一类数据进行批量的逻辑删除(将所有 isdelete=False 的数据修改成 isdelete=True)
3.5 查看所有 isdelete=False 的数据
3.6 查看所有 isdelete=True 的数据

具体的操作步骤:

步骤一:准备测试数据

[root@mariadb ~]# mysql -uroot -p
MariaDB [(none)]> use test;
MariaDB [test]> update test_student SET isdelete=0 WHERE test_student.isdelete=1;
MariaDB [test]> quit;

步骤二:通过自定义 manager 管理器对某个数据进行单个的逻辑删除
2.1 创建一个自定义 manager 管理器的类

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

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

class CustomManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = CustomManager()

    show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete
......

修改为:

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

class CustomManager(Manager):
    #def all(self):
    #    return Manager.all(self).filter(isdelete=True)

    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    #objects = CustomManager()

    #show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete

    def delete(self, using=None, keep_parents=False):
        self.isdelete = True
        self.save()

......

(补充:这里以将 delete 重写成将 isdelete 设置为 True 为例)

2.2 进入相应的 Django 环境

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

2.3 通过自定义 manager 管理器查询数据

>>> Student.objects.all()
<QuerySet [<Student: student:False>, <Student: student:False>, <Student: student:False>]>

2.4 通过自定义 manager 管理器逻辑删除第一条数据(将第一条数据的 isdelete=False 修改成 isdelete=True)

>>> Student.objects.first().delete()

2.5 通过自定义 manager 管理器查询删除后的数据

>>> Student.objects.all()
<QuerySet [<Student: student:True>, <Student: student:False>, <Student: student:False>]>

(补充:这里第一条数据 isdelete=True)

步骤三:通过自定义 manager 管理器对一类数据进行批量的逻辑删除
3.1 创建一个自定义 manager 管理器的类

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

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

class CustomManager(Manager):
    #def all(self):
    #    return Manager.all(self).filter(isdelete=True)

    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)
   
class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    #objects = CustomManager()

    #show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete

    def delete(self, using=None, keep_parents=False):
        self.isdelete = True
        self.save()

......

修改为:

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

class CustomManager(Manager):
    #def all(self):
    #    return Manager.all(self).filter(isdelete=True)

    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=True)

class DeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=True)
   
class BatchDelManager(Manager):
    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=False)

    def filter(self, *args, **kwargs):
        #1. Get the record that needs to be deleted
        delList = Manager.get_queryset(self)

        #2. Define the closure method to modify isdelete = true
        def delete1(delqueryset):
            for dq in delqueryset:
                dq.isdelete = True
                dq.save()
        #3. Create an instance method dynamically, declare that delete has a delete method, call interface is delete (delist), call the delete1 object to execute
        import types
        delList.delete = types.MethodType(delete1,delList)

        return delList

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = BatchDelManager()

    show = DeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete

    def delete(self, using=None, keep_parents=False):
        self.isdelete = True
        self.save()

......


补充:
1) 这里以添加一个将父类的 all 重写成将所有 isdelete=True 的数据修改成 isdelete=False 的 BatchDelManager(Manager) 对象并在 Student 类中使用 objects 调用为例
2) 这里的实现方法是:动态创建一个实例方法,对外声明 delete 有一个 delete 方法调用接口是 delete(deList) ,调用 delete1 对象进行执行
3) 这里的 DeletedManager(Manager) 会查看所有 isdelete=True 的数据,并通过 Student 类中的 show 调用
4) 只要子类重写了父类的方法,就不会掉用父类的方法了,而是调用子类的方法
5) 闭包的作用是内部执行一个结果,对外还是一个外部函数的一个调用
6) python2 使用是 new 模块的 instancemethod 属性实现此功能,而 python3 使用是 types 模块的 MethodType属性实现此功能

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 test.models import *

3.3 查看所有 isdelete=False 的数据

>>> Student.objects.all()
<QuerySet [<Student: student:False>, <Student: student:False>]>

(补充:这里的 objects 已经经过了重写,所以只能显示 isdelete=False 的数据)

3.4 通过自定义 manager 管理器对一类数据进行批量的逻辑删除(将所有 isdelete=False 的数据修改成 isdelete=True)

>>> Student.objects.filter().delete()

3.5 查看所有 isdelete=False 的数据

>>> Student.objects.all()
<QuerySet []>

(补充:此时已经没有 isdelete=False 的数据)

3.6 查看所有 isdelete=True 的数据

>>> Student.show.all()
<QuerySet [<Student: student:True>, <Student: student:True>, <Student: student:True>]>