Python Django框架之原生SQL语句使用(6)

一、Django连接数据库

在之前的文章我们有说到过,django的数据库默认初始配置是使用sqlite数据库的,要想使用mysql作为数据库,需在settings.py中改变连接配置信息。
mysql配置及安装详情:点击查看mysql详细配置



二、原生sql操作数据库

使用Django来操作MySQL时,底层还是通过Python来操作的,因此要想用Django来操作MySQL,首先需要安装驱动程序。
在Python3中,驱动程序有多种选择,包括pymysql、mysqlclient等。

如果已经按照上面文章配置完毕后,是可以导入pymysql的,所以这里我们就使用pymysql进行操作。

1.表结构的设计

在这篇文章中,我们将通过案例的方式来使用pymysql,而我们需要做的案例是学员管理系统,和做项目是一样的,表结构设计永远都是第一步,那么做学员管理系统,首先我们要想,肯定是要有班级,老师及学生的,且老师可以教多个班级,班级和学生要关联起来,老师和班级也要关联起来,但是考虑到老师可以任教多个班级,所以老师和班级的关系表需在多创建一张表。

首先先创建一个数据库xxx:

create database xxx

在创建class表:

CREATE TABLE class(
id INT PRIMARY KEY auto_increment,
title VARCHAR(20)
)

在创建学生表:

CREATE TABLE Student(
id INT PRIMARY KEY AUTO_INCREMENT,
stu_name CHAR(20) NOT NULL,
class_id INT,
FOREIGN KEY(class_id) REFERENCES Class(id) ON DELETE CASCADE ON UPDATE CASCADE
)CHARSET utf8;

在创建老师表:

CREATE TABLE Teacher(
id INT PRIMARY KEY auto_increment,
th_name CHAR(20) NOT NULL
)charset utf8;

最后在创建老师和班级的关联表:

CREATE TABLE teachers( 
id INT PRIMARY KEY auto_increment,
t_id INT,
c_id INT,
FOREIGN KEY(t_id) REFERENCES Teacher(id) on delete cascade on update cascade,
FOREIGN KEY(c_id) REFERENCES Class(id) on delete cascade on update cascade
)charset utf8;

表结构设计完成后,我们就可以进行下一步的操作了。

2.pymysql操作数据库

通过上述操作对mysql创建表成功后,我们就可以进行添加操作了,为了方便演示pymysql是怎么操作的,这里就以班级表进行添加操作。

不管是使用pymysql或者是mysqlclient或者是mysqldb,接口都是一样的。

Python DB API规范下cursor对象常用接口如下:

接口含义
description如果cursor执行了SQL语句,那么执行cursor.description属性会返回一个列表,这个列表中装的是元组,元组中装的分别是(name,type_code,display_size,internal_size,precision,scale,null_ok),其中name代表的是查找出来的数据的字段名称。
rowcount代表的是在执行了SQL语句后受影响的行数。
close关闭游标,关闭游标以后就再也不能使用了,否则会抛出异常。
execute(sql[,parameters])执行SQL语句,还可以根据需要传递参数,定义parameters属性即可。
fetchone在执行了查询操作以后,获取第一条数据。
fetchmany(size)在执行查询操作以后,获取多条数据,具体是多少条要看传的size参数,如果不传size参数,那么默认是获取第一条数据。
fetchall获取所有满足sql语句的数据。
commit提交添加数据到数据库

首先在根目录创建一个app01的文件夹之后在创建一个views.py来存放我们后面操作的代码。

urls.py如下:

from django.urls import path
from app01 import views

urlpatterns = [
    path('add_class/', views.add_class, name='add_class'),
]

app01/views.py如下:

from django.shortcuts import render, HttpResponse
import pymysql


def add_class(request):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='xxx')
    # 转换成字典类型
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("INSERT INTO class(teacher_name) VALUES (%s)", ['全栈1班', ])
    conn.commit()
    cursor.execute("select * from class", [])
    classes = cursor.fetchall()
    print(classes)
    cursor.close()
    conn.close()
    return HttpResponse('ok')

此时访问http://127.0.0.1:8000/add_class/,控制台打印:

[{'id': 1, 'teacher_name': '全栈1班'}]

3.数据库连接优化

通过上述代码,我们可以发现,当我们每次执行一次视图函数都会建立起连接和关闭连接,反反复复,在人流量较大的情况下,会给数据库造成很大的压力,因此为了防止数据库反复建立、断开连接及代码优化,我们可以定义一个类,需要时在调用。

新建文件夹SQL_connection/sqlheper.py如下:

import pymysql

class SqlHelper(object):

    def __init__(self):
        self.conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='xxx')
        self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)

    # 获取多个
    def get_list(self, sql, args):
        self.cursor.execute(sql, args)
        result_list = self.cursor.fetchall()
        return result_list

    # 获取单个
    def get_one(self, sql, args):
        self.cursor.execute(sql, args)
        result = self.cursor.fetchone()
        return result

    # 添加、删除不返回方法
    def modify(self, sql, args):
        self.cursor.execute(sql, args)
        self.conn.commit()

    # 支持批量存入一个列表元组
    def multiple_modify(self, sql, args):
        self.cursor.executemany(sql, args)
        self.conn.commit()

    # 添加、删除返回id操作
    def create(self, sql, args):
        self.cursor.execute(sql, args)
        self.conn.commit()
        return self.cursor.lastrowid

    # 关闭操作
    def close(self):
        self.cursor.close()
        self.conn.close()

app01/views.py如下:

from django.shortcuts import render, HttpResponse

from SQL_connection.sqlheper import SqlHelper


def add_class(request):
    nid = '全栈4班'
    obj = SqlHelper()
    obj.modify("INSERT INTO class(teacher_name) VALUES (%s)", [nid, ])
    data = obj.get_list('select * from class', [])
    print(data)
    obj.close()

    return HttpResponse('ok')

此时访问http://127.0.0.1:8000/add_class/,控制台打印:

[{'id': 1, 'teacher_name': '全栈一班'},{'id': 2, 'teacher_name': '全栈4班'}]

显然我们可以发现代码更加的整洁,且也不用在数据库反复的进行连接操作了。



三、案例-学员管理系统

使用原生SQL方式实现一个学员管理系统,完成图书的增删查和前端页面展示。



1.班级列表



一、班级首页


urls.py如下:
from django.urls import path
from app01 import views

urlpatterns = [
    path('add_class/', views.add_class, name='add_class'),
    path('classes/', views.classes, name='classes')
]

app01/views.py如下:

from django.shortcuts import render, HttpResponse

from SQL_connection.sqlheper import SqlHelper



def classes(request):
    obj = SqlHelper()
    class_list = obj.get_list("select * from class", [])
    return render(request, 'classes.html', {'class_list': class_list})

classes.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>班级列表</h1>
    <a href="#">添加班级</a>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>班级名称</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for row in class_list %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ row.title }}</td>
                    <td>
                        <a href="#">编辑</a>
                        |
                        <a href="#">删除</a>
                    </td>
                </tr>
            {% endfor %}

        </tbody>
    </table>
</body>
</html>

此时访问127.0.0.1:8000/classes/如下:
在这里插入图片描述
显然我们之前创建的班级列表全部都显示出来了。



二、班级添加


由于我们已经封装好了一个类,所以如果想添加班级,只需要在添加一个路由、视图函数、保存、跳转。 由此:
  1. 添加一个路由
  2. 视图函数
  3. 保存数据到数据库
  4. 跳转到班级页面

因为之前的示例添加和班级表添加类似,所以只需修改一下就可以当作班级添加使用了。

urls.py如下:

from django.urls import path
from app01 import views

urlpatterns = [
    path('add_class/', views.add_class, name='add_class'),
    path('classes/', views.classes, name='classes')
]

add_class.html:如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>班级添加</h1>
    <form action="{% url 'add_class' %}" method="post">
        {% csrf_token %}
        <p>班级名称:<input type="text" name="title"></p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper
    
def add_class(request):
    if request.method == "GET":
        return render(request, 'add_class.html')
    # post请求
    nid = request.POST.get('title')
    obj = SqlHelper()
    obj.modify("INSERT INTO class(title) VALUES (%s)", [nid, ])
    obj.close()
    return redirect('classes')

classes.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>班级列表</h1>
    <a href="{% url 'add_class' %}">添加班级</a>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>班级名称</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for row in class_list %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ row.title }}</td>
                    <td>
                        <a href="#">编辑</a>
                        |
                        <a href="#">删除</a>
                    </td>
                </tr>
            {% endfor %}

        </tbody>
    </table>
</body>
</html>

此时访问127.0.0.1:8000/classes/如下:
在这里插入图片描述
显然,视图函数执行了post请求并成功的保存到数据库,进行跳转页面。



三、班级删除


班级的删除和添加有点不一样,因为如果想要删除一个班级,我们必须知道他的一个条件,而拿什么条件会更好呢,我们一般会拿id,因为id是唯一的,不会重复,所以我们可以通过获取到在url里加上一个get请求参数、创建路由、视图函数、跳转。
  1. 在班级首页删除a标签的url里加上一个get参数(参数为id)
  2. 创建删除视图函数
  3. 删除成功跳转到班级首页

urls.py如下:

from django.urls import path
from app01 import views

urlpatterns = [
    path('add_class/', views.add_class, name='add_class'),
    path('classes/', views.classes, name='classes'),
    path('del_class/', views.del_class, name='del_class'),
]
	

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper

def del_class(request):
    obj = SqlHelper()
    nid = request.GET.get('class_id')
    obj.modify('delete from class where id=%s', [nid])
    obj.close()
    return redirect('classes')

classes.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>班级列表</h1>
    <a href="{% url 'add_class' %}">添加班级</a>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>班级名称</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for row in class_list %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ row.title }}</td>
                    <td>
                        <a href="#">编辑</a>
                        |
                        <a href="{% url 'del_class' %}?class_id={{ row.id }}">删除</a>
                    </td>
                </tr>
            {% endfor %}

        </tbody>
    </table>
</body>
</html>

此时访问127.0.0.1:8000/classes/如下:
在这里插入图片描述
如上述所属,点击删除后,数据将在数据库删除后展示在班级页面上。



四、班级编辑


班级的编辑操作和班级删除类似,不过班级的编辑操作,需要点击a标签编辑,需要编辑的内容需显示出来,且还要携带相应的id。所以在发送get请求的时候我们需要获取要编辑的班级的id、获取到id后通过数据库查询获取修改内容,在把获取到的值传给后台的模板进行渲染,展示。
  1. 创建编辑路由
  2. 创建编辑的视图函数
  3. 通过get的方式传id给后台
  4. 通过id向数据库查询修改内容
  5. 点击编辑标签显示编辑的内容
  6. post请求成功后通过id作为条件、内容修改班级
  7. 跳转到班级页面

urls.py如下:

from django.urls import path
from app01 import views

urlpatterns = [
    path('add_class/', views.add_class, name='add_class'),
    path('classes/', views.classes, name='classes'),
    path('del_class/', views.del_class, name='del_class'),
    path('edit_class/', views.edit_class, name='edit_class'),
]

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper


def edit_class(request):
    obj = SqlHelper()
    if request.method == "GET":
        nid = request.GET.get('class_id')
        class_dict = obj.get_one('select id,title from class where id=%s', [nid, ])
        obj.close()
        return render(request, 'edit_class.html', {'class_dict': class_dict})
    nid = request.GET.get('nid')
    title = request.POST.get('title')
    obj.modify('update class set title=%s where id=%s', [title, nid, ])
    obj.close()
    return redirect('classes')

edit_class.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>班级编辑</h1>
    <form action="{% url 'edit_class' %}?nid={{ class_dict.id }}" method="post">
        {% csrf_token %}
        <p>班级名称:<input type="text" name="title" value="{{ class_dict.title }}"></p>
        <input type="submit" value="提交">
    </form>
</body>
</html>

classes.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>班级列表</h1>
    <a href="{% url 'add_class' %}">添加班级</a>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>班级名称</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for row in class_list %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ row.title }}</td>
                    <td>
                        <a href="{% url 'edit_class' %}?class_id={{ row.id }}">编辑</a>
                        |
                        <a href="{% url 'del_class' %}?class_id={{ row.id }}">删除</a>
                    </td>
                </tr>
            {% endfor %}

        </tbody>
    </table>
</body>
</html>

此时访问127.0.0.1:8000/classes/如下:
在这里插入图片描述
可以看到,get请求通过获取id来展示修改内容,而post请求通过获取的id作为条件去修改班级名称。



2.学生列表



一、学生首页


自此班级列表的展示就已经完成了,学生列表和班级列表类似,所以这里就直接将学生相应所需的视图函数、路由、模板写上,后面再进行相应操作。


因为现在还没有添加学生成员,为了看效果,我们主动在数据库添加两位学生,方便展示。

数据库增加两名学生(这里条件的id填你班级的id):

INSERT INTO student(stu_name,class_id) VALUES('小红',7)
INSERT INTO student(stu_name,class_id) VALUES('小蓝',6)

urls.py如下:

from django.urls import path
from app01 import views

urlpatterns = [
    # 班级列表
    path('add_class/', views.add_class, name='add_class'),
    path('classes/', views.classes, name='classes'),
    path('del_class/', views.del_class, name='del_class'),
    path('edit_class/', views.edit_class, name='edit_class'),
    # 学生列表
    path('students/', views.students, name='students'),
    path('add_student/', views.add_student, name='add_student'),
    path('del_student/', views.del_student, name='del_student'),
    path('edit_student/', views.edit_student, name='edit_student'),

]

students.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>学生列表</h1>
    <a href="{% url 'add_student' %}">添加学生</a>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>学生名称</th>
                <th>班级</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for row in student_list %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ row.stu_name }}</td>
                    <td>{{ row.title }}</td>
                    <td>
                        <a href="{% url 'edit_student' %}?student_id={{ row.id }}">编辑</a>
                        |
                        <a href="{% url 'del_student' %}?student_id={{ row.id }}">删除</a>
                    </td>
                </tr>
            {% endfor %}

        </tbody>
    </table>
</body>
</html>

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper


def students(request):
    obj = SqlHelper()
    student_list = obj.get_list(
        "SELECT stu.id,stu.`stu_name`,class_id,title FROM student AS stu INNER JOIN class AS cls ON stu.`class_id`=cls.`id`",
        [])
    obj.close()
    print(student_list)
    return render(request, 'students.html', {'student_list': student_list})


def add_student(request):
    return render(request, 'add_student.html')


def del_student(request):
    return redirect('students')


def edit_student(request):
    return render(request, 'edit_student.html')

此时访问127.0.0.1:8000/students/如下:
在这里插入图片描述
此时插入的学生列表的数据就全部的展示出来了。



二、学生添加


学生列表展示完成后,就需要给学生做添加处理,学生添加的方法也和班级添加的方法类似,只需修改一些条件,给学生列表的添加附上添加路由,给url做上视图、模板、返回到学生列表即可,因为学生班级需要选择,所以在视图中还需要获取所有的班级列表。
  1. 获取班级列表
  2. 通过get请求展示界面
  3. 通过post请求获取增加的值(获取班级id需要select标签的name属性即可获取
  4. 在添加视图中做sql查询增加操作
  5. 添加成功跳转会学生列表

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper


def add_student(request):
    if request.method == "GET":
        obj = SqlHelper()
        class_list = obj.get_list('select id,title from class', [])
        return render(request, 'add_student.html', {'class_list': class_list})
    # post请求
    title = request.POST.get('title')
    class_id = request.POST.get('class_id')
    obj = SqlHelper()
    obj.modify('insert into student(stu_name,class_id) values(%s,%s)', [title, class_id])
    obj.close()
    return redirect('students')


add_student.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>学生添加</h1>
    <form action="{% url 'add_student' %}" method="post">
        {% csrf_token %}
        <p>学生名称:<input type="text" name="title"></p>
        <p>
            学生班级
            <select name="class_id">
                {% for row in class_list  %}
                    <option value="{{ row.id }}">{{ row.title }}</option>
                {% endfor %}
            </select>
        </p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

此时访问127.0.0.1:8000/students/如下:

在这里插入图片描述



三、学生删除


学生的删除和班级的删除也是差不多的,万变不离其中,只需要获取到学生的唯一id即可删除,我们可以通过get形式获取到id,然后通过数据库删除、跳转会学生列表即可。
  1. 通过get请求携带着学生的id
  2. 视图接收到学生id
  3. 通过学生id进行数据库删除
  4. 跳转回学生列表

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper



def del_student(request):
    student_id = request.GET.get('student_id')
    obj = SqlHelper()
    obj.modify('delete from student where id=%s', [student_id, ])
    obj.close()
    return redirect('students')


此时访问127.0.0.1:8000/students/如下:
在这里插入图片描述
可以看到,访问成功后,页面跳转会了学生列表,且视图函数执行了删除的操作。



四、学生编辑


学生编辑和班级的编辑类似,不过学生在点击编辑标签时,我们需要将当前学生的内容展示出来,且是哪个班级的也需要展示,因为如果当我们本来不想编辑,但是却点了提交,班级第一个展示的也不是自己班级,导致班级被修改了。所以,我们需要在班级展示的时候给它选择一个所属班级,那么就要进行id的判断,通过get传学生id无疑是必要的,且还需要使用option标签的 selected属性,表示第一个班级的选中状态。
  1. 给学生列表的编辑添加get传学生id
  2. 在get请求时通过学生id获取班级信息
  3. 在学生列表展示的时候加上判断
  4. 判断成功后添加option标签的selected属性
  5. post请求提交到视图
  6. 视图通过传来的学生id进行学生姓名、班级id的数据库更新
  7. 成功后跳转回学生列表

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper


def edit_student(request):
    obj = SqlHelper()
    if request.method == "GET":
        class_id = request.GET.get('student_id')

        student_class = obj.get_one("SELECT stu.id,stu.`stu_name`,class_id,title FROM student as stu \
                                    INNER JOIN class as cls ON stu.`class_id`=cls.`id` \
                                    where stu.id=%s ", [class_id, ])

        class_list = obj.get_list('select id,title from class', [])
        context = {
            'class_list': class_list,
            'student_class': student_class,
        }
        obj.close()
        return render(request, 'edit_student.html', context)

    nid = request.GET.get('nid')
    title = request.POST.get('title')
    class_id = request.POST.get('class_id')
    obj.modify('update student set stu_name=%s,class_id=%s where id=%s', [title, class_id, nid, ])
    obj.close()
    return redirect('students')

edit_student.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
        <h1>编辑学生</h1>
        <form method="post" action="{% url  'edit_student' %}?nid={{ student_class.id }}">
            {% csrf_token %}
            <p>学生名称:<input type="text" name="title" value="{{ student_class.stu_name }}" /></p>
            <p>
                    所属班级
                    <select name="class_id">
                        {% for row in class_list  %}
                            {% if row.id == student_class.class_id %}
                                <!-- 如果这里班级id等于当前编辑的班级id则替换到当前班级id所属的班级名字!-->
                                 <option selected value="{{ row.id }}">{{ row.title }}</option>
                            {% else %}
                                <option value="{{ row.id }}">{{ row.title }}</option>
                            {% endif %}
                        {% endfor %}
                    </select>
                </p>
            <input type="submit" value="提交" />
        </form>
</body>
</html>

此时访问127.0.0.1:8000/students/如下:

在这里插入图片描述
可以看到在编辑页面时,班级是正确的,且提交成功后也进行了数据库的更改及跳转学生列表。


3.老师列表

最后还有一个老师列表,和上述班级、学生列表操作是类似的,不过是获取的时候多了一张表,通过两次的关联就可以获取到相应的值了。因为老师列表的视图及模板都类似,所以这里就先全部定义了,要写视图函数的时候在写上。


一、老师首页

因为之前没有插入老师及与老师关联的班级表数据,所以我们可以先向数据库添加:

insert into teacher(th_name) value('大白')
INSERT INTO teacher(th_name) VALUE('大黑')

insert INto teachers(t_id,c_id) value(9,6)
INSERT INTO teachers(t_id,c_id) VALUE(9,20)
insert INto teachers(t_id,c_id) value(10,7)

这里每个人的班级id、老师id不一样,根据自己班级id及老师id做插入.


urls.py如下:

from django.urls import path
from app01 import views

urlpatterns = [
    # 班级列表
    path('add_class/', views.add_class, name='add_class'),
    path('classes/', views.classes, name='classes'),
    path('del_class/', views.del_class, name='del_class'),
    path('edit_class/', views.edit_class, name='edit_class'),
    # 学生列表
    path('students/', views.students, name='students'),
    path('add_student/', views.add_student, name='add_student'),
    path('del_student/', views.del_student, name='del_student'),
    path('edit_student/', views.edit_student, name='edit_student'),
    # 老师列表
    path('teachers/', views.teachers, name='teachers'),
    path('add_teacher/', views.add_teacher, name='add_teacher'),
    path('del_teacher/', views.del_teacher, name='del_teacher'),
    path('edit_teacher/', views.edit_teacher, name='edit_teacher'),
]

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper

def teachers(request):
    obj = SqlHelper()
    # 通过两次关联表获取到老师相关的数据
    teacher_list = obj.get_list("SELECT teacher.id AS tid,th_name,class.`id` AS 
    												cid,class.`title` FROM teachers \
                                 INNER JOIN teacher ON teachers.`t_id`=teacher.`id` \
                                INNER JOIN class ON class.`id`=teachers.`c_id` ", [])
    result = {}
    for teacher in teacher_list:
        tid = teacher['tid']
        # 是否已经创建了该列表
        if tid in result:
            result[tid]['titles'].append(teacher['title'])
            result[tid]['cid'].append(teacher['cid'])
        else:
            result[tid] = {'tid': teacher['tid'], 'th_name': teacher['th_name'], 'cid': [teacher['cid'], ],'titles': [teacher['title'], ]}
                           
    obj.close()
    print(result.values)
    return render(request, 'teachers.html', {'result': result.values()})


def add_teacher(request):
    pass


def del_teacher(request):
    pass

def edit_teacher(request):
    pass

因为老师任教的班级可能有多个,所以我们可以通过id作为key,相同id的值作为value,将相同id的班级id和班级姓名在嵌套一层,班级姓名为titles、班级id为cid,这样所有数据就可以存在一个字典中了,打印result结果:

{9: {'tid': 9, 'th_name': '大白', 'cid': [6, 7], 'titles': ['全栈1班', '全栈4班']}, 10: {'tid': 10, 'th_name': '大黑', 'cid': [7, 16, 20], 'titles': ['全栈4班', '全栈5班', '全栈66班']}}


teachers.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>老师列表</h1>
    <a href="{% url 'add_teacher' %}">添加</a>
    <table border="1">
        <thead>
        <tr>
            <th>ID</th>
            <th>班级</th>
            <th>教师名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
            {% for row in result %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>
                        {% for class in row.titles %}
                            <span style="border: 1px solid red">{{ class }}</span>
                        {% endfor %}
                    </td>
                    <td>
                        {{ row.th_name }}
                    </td>
                    <td>
                        <a href="{% url 'edit_teacher' %}?teacher_id={{ row.tid }}&cid={{ row.cid }}">编辑</a>
                        <a href="{% url 'del_teacher' %}?teacher_id={{ row.tid }}">删除</a>
                    </td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
</html>

此时访问127.0.0.1:8000/teachers/如下:
在这里插入图片描述



二、老师添加


老师添加操作和上述班级、学生的添加操作都是类似的,不过就是select标签多了一个多选的选项。


app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper


def add_teacher(request):
    obj = SqlHelper()
    if request.method == "GET":
        class_list = obj.get_list('select * from class ', [])
        return render(request, 'add_teacher.html', {'class_list': class_list})
    else:
        class_list_id = request.POST.getlist('class_list_id')
        teacher_name = request.POST.get('title')
        teacher_id = obj.create("insert into teacher(th_name) value(%s)", [teacher_name, ])
        data_list = [(teacher_id, class_id) for class_id in class_list_id]
        obj.multiple_modify("insert into teachers(t_id,c_id) value(%s,%s)", data_list)
        return redirect('teachers')

add_teacher.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>添加老师</h1>
    <form action="{% url 'add_teacher' %}" method="post">
        {% csrf_token %}
        <p>老师姓名:<input type="text" name="title"></p>
        <p>
            任教班级:
            <select name="class_list_id" multiple>
                {% for row in class_list %}
                    <option value="{{ row.id }}">{{ row.title }}</option>
                {% endfor %}
            </select>
        </p>
        <input type="submit" value="提交">
    </form>
</body>
</html>

此时访问127.0.0.1:8000/teachers/如下:
在这里插入图片描述
可以看到数据已经添加成功并返回给模板了。



三、老师删除


老师删除的操作就更简单了,这里就不详细说明了。


app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper

def del_teacher(request):
    obj = SqlHelper()
    teacher_id = request.GET.get('teacher_id')
    obj.modify('delete from teacher where id=%s', [teacher_id, ])
    # 因为数据库设计的时候是级联删除(不写这行也行)
    obj.modify('delete from teachers where t_id=%s', [teacher_id, ])
    return redirect('teachers')

此时访问127.0.0.1:8000/teachers/如下:
在这里插入图片描述
可以看到数据已经删除成功了。


四、老师编辑


最后到了老师编辑,这里涉及到的知识点就有点多了,因为在编辑表的时候,所任教的班级需要显示, 且还可能是任教多个班级,当提交编辑表单的时候还需要判断,还需要在更新到数据库中,如果是少选或者多选都要进行数据库的操作,因此在post请求有两种方法可以提交数据到数据库:
  • 方法一、
    • 1.在编辑老师的时候获取老师id
    • 2.通过老师id删除所有相关联的班级
    • 3.通过编辑获取到的老师名字,通过老师id进行数据库更新
    • 4.获取到post传来的班级id(通过getlist获取多个)
    • 5.将获取到的班级id依次添加到数据库中
  • 方法二、
    • 1.在编辑老师的时候获取老师id、对应班级id
    • 2.将获取到的班级id用json解析成列表
    • 3.新建一个空列表(用于存放需要删除、增加的数据)[是删除还是添加却决于获取到班级id是否到之前的班级id]
    • 4.通过分类完成,将该删除和添加的数据分成两份,最后使用sql语句将其删除、增加。


app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper

def edit_teacher(request):
    obj = SqlHelper()
    cid = json.loads(request.GET.get('cid'))
    if request.method == "GET":
        teacher_id = request.GET.get('teacher_id')
        teacher = obj.get_one("select * from teacher where id=%s", [teacher_id, ])
        class_list = obj.get_list("select * from class", [])
        context = {
            'teacher': teacher,
            'class_list': class_list,
            'cid': cid
        }
        return render(request, 'edit_teacher.html', context)
    else:
        class_list_id = request.POST.getlist('class_list_id')
        title = request.POST.get('title')
        teacher_id = request.GET.get('teacher_id')
        obj.modify('update teacher set th_name=%s where id=%s ', [title, teacher_id])
    	"""第一种方法"""
        obj.modify('delete from teachers where t_id=%s', [teacher_id, ])
        data_list = [(teacher_id, cls) for cls in class_list_id]
        obj.multiple_modify('insert into teachers(t_id,c_id) value (%s,%s)', data_list)
        obj.close()
        return redirect('teachers')

edit_teacher.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>编辑老师</h1>
    <form action="{% url 'edit_teacher' %}?teacher_id={{ teacher.id }}&cid={{ cid }}" method="post">
        {% csrf_token %}
        <p>
            老师姓名:<input type="text" name="title" value="{{ teacher.th_name }}">
        </p>
        <select name="class_list_id" multiple>
            {% for row in class_list %}
                {% if row.id in cid %}
                    <option selected value="{{ row.id }}">{{ row.title }}</option>
                {% else %}
                    <option value="{{ row.id }}">{{ row.title }}</option>
                {% endif %}
            {% endfor %}
        </select>
        <input type="submit" value="提交">
    </form>
</body>
</html>

此时访问127.0.0.1:8000/teachers/如下:
在这里插入图片描述
可以看到通过方法一是可以完成编辑操作的。


如果使用方法二,也同样可以实现。

app01/views.py如下:

from django.shortcuts import render, HttpResponse, redirect

from SQL_connection.sqlheper import SqlHelper
import json

def edit_teacher(request):
    obj = SqlHelper()
    cid = json.loads(request.GET.get('cid'))
    if request.method == "GET":
        teacher_id = request.GET.get('teacher_id')
        teacher = obj.get_one("select * from teacher where id=%s", [teacher_id, ])
        class_list = obj.get_list("select * from class", [])
        context = {
            'teacher': teacher,
            'class_list': class_list,
            'cid': cid
        }
        return render(request, 'edit_teacher.html', context)
    else:
        class_list_id = request.POST.getlist('class_list_id')
        title = request.POST.get('title')
        teacher_id = request.GET.get('teacher_id')
        obj.modify('update teacher set th_name=%s where id=%s ', [title, teacher_id])
        """第二种方法"""
     	 # 如果是在小于的情况下就是添加大于的情况接收删除
        cls = []
        if len(class_list_id) <= len(cid):
            for class_id in class_list_id:
                if int(class_id) in cid:
                    cid.remove(int(class_id))
                else:
                    cls.append((teacher_id, class_id))
            obj.multiple_modify('insert into teachers(t_id,c_id) value(%s,%s)', cls)
            for row in cid:
                obj.modify('delete from teachers where c_id=%s and t_id=%s', [str(row), teacher_id])
            obj.close()
        else:
            for class_id in cid:
                if str(class_id) in class_list_id:
                    class_list_id.remove(str(class_id))
                else:
                    cls.append(class_id)

            cls_list = [(teacher_id, str(class_id)) for class_id in cls]
            obj.multiple_modify('delete from teachers where t_id=%s and c_id=%s', cls_list)
            data_list = [(teacher_id, class_id) for class_id in class_list_id]
            obj.multiple_modify('insert into teachers(t_id,c_id) value(%s,%s)', data_list)
            obj.close()
    
        return redirect('teachers')

此时访问127.0.0.1:8000/teachers/如下:
在这里插入图片描述
此时通过方法二也可以实现。


我们通过这两次方法可以看到,两种的执行效率不一样,方法一的优点在于删除很快,缺点在于增加需要全部重新增加,且如果在删除全部的时候准备增加的时候,报错了那么数据就消失了。而方法二的优点在于,增加的时候不需要在数据库过多的操作增加很快,且不会重复增加班级、删除也会根据用户选择的班级,进行判断删除,不过缺点也是在于如果用户从多个班级替换到单个班级,那么在删除数据库表的时候就要删除多次。所以每个方法都各有所长,各有所短,根据实际情况使用。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值