Django学生信息管理系统 ---- 第5章


Github:https://github.com/ThanlonSmith/stu-django
博主极力推荐的Python面试教程,有时间的小伙伴可以看看:

Python 面试100讲(基于Python3.x)

1. 数据库表的结构设计
# 创建test数据库
create database test default character set utf8;
# 创建学生表
create table student(id int auto_increment primary key,name varchar(10) not null,class_id int not null);
# 创建班级表
create table class(id int auto_increment primary key, title varchar(20) not null);
# 创建教师表
create table teacher(id int auto_increment primary key,name varchar(10) not null);
# 创建教师班级表
create table teacher2class(id int primary key auto_increment,teacher_id int not null,class_id int not null);
2. 后台引入母板

把重复用到的html代码放到一个html文件中,这个html文件被称为母板,需要用到这些代码的模板可以直接继承这个母板。这个html文件使用的标签是:{% block xxx %} {% endblock %},{% extends '母板.html'%}

3. 查询班级信息

首先要向班级表中插入一条测试数据:

insert class values(null,'软件工程'),(null,'计算机科学与技术');

可以在项目名所在的目录下创建一个名为 app01 的目录,并在该目录下创建 views.py 文件,下面开始在 urls.py 文件中加入查询班级的路由:

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    # 查询班级信息的路由以及对应的函数(对应views下的classes函数)
    path('classes/', views.classes),
]

views 下的 classes 函数写查询班级信息的逻辑代码:

# 导入返回模板的函数render和重定向的redirect函数
from django.shortcuts import render, redirect
# 导入pymysql模块用来连接数据库,这里暂时使用pymysql
import pymysql

def classes(request):
    '''
    查询班级id、班级名称
    :param request:对象相关的数据
    :return:渲染后的模板
    '''
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql语句
    cursor.execute("select id,title from class")
    # 获取查询到的所有信息
    classes_list = cursor.fetchall()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    # 返回模板和数据
    return render(request, 'classes.html', {'classes_list': classes_list})

templates 文件夹下新建 classes.html 文件,也就是我们的模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级信息</title>
</head>
<body>
<p><a href="/add-class/">添加</a></p>
{% for row in classes_list %}
    <tr>
        <td>{{ row.id }}</td>
        <td>{{ row.title }}</td>
    </tr>
    <br>
{% endfor %}
</body>
</html>

查询班级信息页面:
在这里插入图片描述

4. 添加班级信息

添加“添加班级信息”的路由,

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('classes/', views.classes),
    path('add-class/', views.add_class),
]

templates 目录下新建名为 add_class.html 的模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加班级信息</title>
</head>
<body>
<h1>添加班级</h1>
<form action="/add-class/" method="post">
    <label>班级名称:</label>
    <input type="text" name="class_title">
    <input type="submit" value="提交">
</form>
</body>
</html>

views.pyadd_class 函数中写添加学生班级信息的逻辑代码:

def add_class(request):
    # 如果是get请求就返回add_class.html模板就可以
    if request.method == 'GET':
        return render(request, 'add_class.html')
    # 如果是post请求则执行下面的代码
    else:
        # 获取班级的标题
        class_title = request.POST.get('class_title')
        # 创建数据库连接对象
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 创建游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 将班级的名称传到sql语句中
        cursor.execute('insert into class(title) values(%s)', class_title)
        # cursor.execute("insert into class(title) values(%s)", [class_title, ])
        # 提交(查询不需要,其它如添加、修改、更新数据是需要执行commit方法才能将数据插入成功)
        conn.commit()
        # 关闭游标
        cursor.close()
        # 关闭连接
        conn.close()
        # 添加之后就会重定向到/classes/路由,会显示添加后的班级
        return redirect('/classes/')

在班级信息页面中点击添加按钮进入添加班级信息界面,添加班级信息后,页面会自动跳转到班级信息页面。

添加班级信息页面效果:
在这里插入图片描述

5. 编辑班级信息

根据客户端传过来的班级id就可编辑班级信息,逻辑代码:

def edit_class(request):
	# 如果是get请求,这里额外也需要查询下数据库,把原来的信息也展示出来
    if request.method == 'GET':
    	# 获取客户端传过来的班级id
        nid = request.GET.get('nid')
        # 创建数据库连接
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 执行游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 执行sql语句
        cursor.execute('select id,title from class where id=%s', nid)
        # 获取查询到的所有数据
        result = cursor.fetchone()
        # 创建游标
        cursor.close()
        # 关闭连接
        conn.close()
        # 返回模板和数据
        return render(request, 'edit_class.html', {'result': result})
    # post请求用来修改班级信息
    else:
        # nid = request.POST.get('nid')  # 放到请求体
        nid = request.GET.get('nid')  # 放到请求头
        title = request.POST.get('title')
        # 创建数据库连接
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 创建游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 执行sql语句
        cursor.execute('update class set title=%s where id = %s', [title, nid])
         # 提交事务
    	conn.commit()
    	# 关闭游标
    	cursor.close()
    	# 关闭连接
    	conn.close()
        return redirect('/classes/')

需要跳转到编辑信息的模板,将其命名为:edit_class.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改班级信息</title>
</head>
<body>
<h3>编辑班级信息</h3>
<form action="/edit-class/?nid={{ result.id }}" method="post">
    <label>班级名称:</label>
    {#    <input type="text"style="display: none" value="{{ result.id }}">#}
    <input type="text" name="title" value="{{ result.title }}">
    <input type="submit" value="提交">
</form>
</body>
</html>

编辑班级信息页面:
在这里插入图片描述

6. 删除班级信息

         浏览器向服务端发送删除数据的请求,服务端接收请求删除数据后向浏览器发送响应,告诉浏览器重定向到 /classes/。服务端向浏览器发送响应的响应头中有 location:http://127.0.0.1:8000/classes/,即是:告诉浏览器向此链接发送一次请求。

         直接删除就可以了,删除的逻辑是:

def del_class(request):
    # 获取客户端传过来的nid,我们要个根据nid来删除数据
    nid = request.GET.get('nid')
    # 创建连接对象
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql语句
    cursor.execute('delete from class where id=%s', nid)
    # cursor.execute("insert into class(title) values(%s)", [class_title, ])
    # 提交事务
    conn.commit()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    return redirect('/classes/')
7. 查询学生信息

首先向学生表中插入测试数据:

insert into student values(null,'thanlon',1);
insert into student values(null,'kiku',2);

查询学生信息的逻辑代码:

def students(request):
    '''
    学生列表
    :param request:封装了请求相关的所有信息
    :return:返回模板和数据
    '''
    # 创建连接对象
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql语句
    cursor.execute(
        'select student.id,student.name,class.title from  student left join class on student.class_id=class.id')
    # 获取查询到的所有数据
    student_list = cursor.fetchall()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    # 返回模板和数据
    return render(request, 'students.html', {'student_list': student_list})

新建显示学生信息的模板 students.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>学生信息</title>
    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
          crossorigin="anonymous">
</head>
<body>
<div class="container" style="margin-top: 20px">
    <div class="row">
        <div class="col-md-4">
            <a class="btn btn-default" href="">添加</a></p>
            <table class="table table-hover text-center">
                <tr>
                    <th class="text-center">ID</th>
                    <th class="text-center">学生姓名</th>
                    <th class="text-center">学生班级</th>
                    <th class="text-center">操作</th>
                </tr>
                {% for row in student_list %}
                    <tr>
                        <td>{{ row.id }}</td>
                        <td>{{ row.name }}</td>
                        <td>{{ row.title }}</td>
                        <td><a href="/">编辑</a> <a href="">删除</a>
                        </td>
                    </tr>
                {% endfor %}
            </table>
        </div>
    </div>
</div>
</body>
</html>

查询学生信息页面:
在这里插入图片描述

8. 添加学生信息

和添加班级信息同样的逻辑:

def add_student(request):
	# 如果是get请求
    if request.method == 'GET':
    	# 创建连接对象
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 创建游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 执行查询的sql语句
        cursor.execute("select id,title from class")
        # 获取查询到的所有数据
        classe_list = cursor.fetchall()
        # 关闭游标
        cursor.close()
        # 关闭连接
        conn.close()
        # 返回模板和数据
        return render(request, 'add_student.html', {'class_list': classe_list})
    # 如果是post请求
    else:
    	# 获取学生的名字
        name = request.POST.get('name')
        # 获取学生的班级id
        class_id = request.POST.get('class_id')
        # 创建连接
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 创建游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 将学生的名字和班级的id信息放到sql中
        cursor.execute("insert into student(name,class_id) values (%s,%s)", [name, class_id, ])
        # 执行事务
        conn.commit()
        # 关闭游标
        cursor.close()
        # 关闭连接
        conn.close()
        # 返回模板
        return redirect('/students/')

下面这部分是模板 add_student.html,注意模板语法的书写:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加学生信息</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container" style="margin-top: 20px">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <form action="/add-student/" method="post">    {#如果没有写,默热提交到当前url#}
                <div class="form-group">
                    <label>姓名:</label>
                    <input type="text" class="form-control" id="" placeholder="" name="name">
                </div>
                <div class="form-group">
                    <select class="form-control" name="class_id">
                        {% for row in class_list %}
                            <option value="{{ row.id }}">{{ row.title }}</option>
                        {% endfor %}
                    </select>
                </div>
                <button type="submit" class="btn btn-primary">添加</button>
            </form>
        </div>
    </div>
</div>
</body>
</html>

添加学生信息页面:
在这里插入图片描述

9. 编辑学生信息

首先写将班级信息和当前学生信息渲染到编辑学生信息模板的逻辑,然后才是编辑学生信息的逻辑:

def edit_student(request):
	"""
	编辑学生信息
	"""
	# get请求时
    if request.method == 'GET':
    	# 获取传过来的学生id
        nid = request.GET.get('nid')
        # 创建连接对象
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 创建游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 执行查询班级信息的sql
        cursor.execute("select id,title from class")
        # 获取所有班级信息
        class_list = cursor.fetchall()
        # 执行查询当前学生编号、名字和班级id的sql
        cursor.execute("select id,name,class_id from student where id=%s", nid)
        # 获取查询到的数据。因为数据只有一条,所以这里使用fetchone()就可以了
        current_student_info = cursor.fetchone()
        # 关闭游标
        cursor.close()
        # 关闭连接
        conn.close()
        # 返回模板和数据
        return render(request, 'edit_student.html',
                      {'class_list': class_list, 'current_student_info': current_student_info})
    # post请求时
    else:
    	# 从url中获取学生的id
        nid = request.GET.get('nid')
        # 从请求体(form表单)中获取当前学生的姓名
        name = request.POST.get('name')
        # 从请求体中获取当前学生的班级id
        class_id = request.POST.get('class_id')
        # 创建练级
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 创建游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 执行sql语句
        cursor.execute("update student set name=%s,class_id=%s where id = %s", [name, class_id, nid])
        # 提交事务
        conn.commit()
        # 关闭游标
        cursor.close()
        # 关闭连接
        conn.close()
        # 重定向到学生信息页面
        return redirect('/students/')

编辑学生信息的模板 edit_student.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加学生信息</title>
</head>
<body>
<div class="container" style="margin-top: 20px">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <form action="/edit-student/?nid={{ current_student_info.id }}" method="post">
                {#            还可以设置input标签将其隐藏#}
                <div class="form-group">
                    <label>姓名:</label>
                    <input type="text" class="form-control" id="" placeholder="" name="name"
                           value="{{ current_student_info.name }}">
                </div>
                <div class="form-group">
                    <select class="form-control" name="class_id">
                        {% for row in class_list %}
                            {% if  row.id == current_student_info.class_id %}
                                <option selected="selected" value="{{ row.id }}">{{ row.title }}</option>
                            {% else %}
                                <option value="{{ row.id }}">{{ row.title }}</option>
                            {% endif %}
                        {% endfor %}
                    </select>
                </div>
                <button type="submit" class="btn btn-primary">更新</button>
            </form>
        </div>
    </div>
</div>
</body>
</html>

编辑学生信息页面:
在这里插入图片描述

10. 删除学生信息

删除学生信息的逻辑,与删除班级相同,也是比较简单的:

def del_student(request):
    '''
    删除学生信息
    '''
    # 获取学生编号
    nid = request.GET.get('nid')
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql
    cursor.execute('delete from student where id=%s', nid)
    # 提交事务
    conn.commit()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    # 返回模板
    return redirect('/students/')
11. Bootstrap介绍

         Bootstrap是一个包含css和js的代码库,有很多已经构建好的组件,模态对话框就是其中的一种,因为接下来要使用到模态对话框,我们直接用就可以这个组件就可以。Bootstrap还支持响应式布局,响应式都是基于css的media来实现的,下面是一个使用media实现响应式的例子:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<style>
    .page-header {
        height: 20px;
        background: rebeccapurple;
    }

    @media (max-width: 1200px) {
        .page-header {
            height: 20px;
            background: yellowgreen; 
        }
    }
    @media (max-width: 1000px) {
        .page-header {
            height: 20px;
            background: lightcoral;
        }
    }
    @media (max-width: 300px) {
        .page-header {
            height: 20px;
            background: saddlebrown;
        }
    }
</style>
<body>
<div class="page-header"></div>
</body>
</html>

         当页面宽度大于等于是1200px的时候,显示yellowgreen的颜色,当页面宽度大于等于是1000px的时候,显示lightcoral的颜色,当页面宽度大于等于300px的时候,显示saddlebrown的颜色。

12. AJAX添加班级信息

添加班级信息的逻辑:

def add_class_modal(request):
	# 获取班级名称
    title = request.POST.get('title')
    # 输入的班级名称的长度需要大于0
    if len(title) > 0:
    	# 创建连接
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 创建游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 执行sql
        cursor.execute('insert into class (title) values (%s)', title)
        # 提交事务
        conn.commit()
        # 关闭游标
        cursor.close()
        # 关闭连接
        conn.close()
        # 向前台返回ok
        return HttpResponse('ok')
    else:
    	# 如果提交过来的班级名称长度是小于0的,向前台返回不能为空,给前台提示信息
        return HttpResponse('班级不能为空!')

添加一个模态对话框用来添加班级信息,由于以Form表单的方式提交,不论班级信息填写正确还是错误都会提交到后台并刷新页面,这样模态框就会消失。所以,我们这里使用AJAX的方式来提交请求,AJAX可以在不刷新页面的情况下与后台交互

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>班级信息</title>
    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
          crossorigin="anonymous">
    <style>
        .hide {display: none;}
        .shadow {position: fixed; top: 0; bottom: 0; left: 0; right: 0; background-color: black; opacity: 0.4; z-index: 999; }
        .modal_layer { position: fixed; z-index: 1000; left: 50%; top: 50%; background-color: white; width: 400px; height: 150px; margin-top: -150px; margin-left: -200px;}
    </style>
</head>
<body>
<div class="container" style="margin-top: 20px">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            {#            <a class="btn btn-default" href="/add-class/">添加</a>#}
            <a class="btn btn-default" id="addClasses">添加班级信息</a>
            <div class="shadow hide" id="shadow"></div>
            <div class="modal_layer hide" id="modal_layer">
                <div class="panel panel-primary">
                    <div class="panel-heading">添加班级信息</div>
                    <div class="panel-body">
                        <form action="/add-class-modal/" method="post">
                            <div class="form-group">
                                <label for="">班级名称</label>
                                <input type="text" name="title" class="form-control" id="title" placeholder=""
                                       autofocus>
                                <span id="error" style="color: red"></span>
                            </div>
                            <input type="button" class="btn btn-primary" value="确认添加" id="add_class">
                        </form>
                    </div>
                </div>
            </div>
            <table class="table table-hover text-center">
                <tr>
                    <th class="text-center">班级ID</th>
                    <th class="text-center">班级名称</th>
                    <th class="text-center">操作</th>
                </tr>
                {% for row in classes_list %}
                    <tr>
                        <td>{{ row.id }}</td>
                        <td>{{ row.title }}</td>
                        <td>
                            <a href="/edit-class/?nid={{ row.id }}">编辑</a> <a href="/del-class/?nid={{ row.id }}">删除</a>
                        </td>
                    </tr>
                {% endfor %}
            </table>
        </div>
    </div>
</div>
</body>
<script
        src="https://code.jquery.com/jquery-3.4.1.js"
        integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
        crossorigin="anonymous"></script>
<script
        src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"
        integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
        crossorigin="anonymous">
</script>
<script>
    $(document).ready(function () {
        $('#addClasses').click(function () {
            $('#shadow').removeClass('hide');
            $('#modal_layer').removeClass('hide');
        });
        $('#add_class').click(function () {
            $.ajax({
                url: '/add-class-modal/',
                type: 'POST',
                data: {'title': $('#title').val()},
                success: function (data) {
                    //当服务端处理完,返回数据时,自动调用该函数
                    if (data == 'ok') {
                        alert('添加成功!');
                        location.href = '/classes/';
                    } else {
                        $('#error').text(data);
                    }
                }
            })
        });
         $('#shadow').click(function () {
            $('#shadow').addClass('hide');
            $('#modal_layer').addClass('hide');
        });
    })
</script>
</html>

模块对话框适用于 少量的输入标签和数据 的情况下,url适用于 操作多、对于大量的数据 的操作。

AJAX添加班级信息页面:
在这里插入图片描述

13. AJAX编辑班级信息

还是使用之前编辑班级信息的逻辑代码,可以在原来的基础上可以加上一些表单字段的判断:

def edit_class(request):
    '''
    编辑班级信息
    '''
    # 获取班级编号
    class_id = request.GET.get('class_id')
    # 获取班级名称
    class_title = request.GET.get('class_title')
    # 获取的名称长度要大于0
    if len(class_title) > 0:
    	# 创建连接
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
        # 创建游标
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        # 执行sql
        cursor.execute('update class set title=%s where id = %s', [class_title, class_id])
        # 提交事务
        conn.commit()
        # 关闭游标
        cursor.close()
        # 关闭连接
        conn.close()
        # 向前台返回的data,前台通过这里来判断编辑是否完成
        return HttpResponse('ok')
    else:
    	# 返回错误提示信息
        return HttpResponse('班级不能为空!')

使用AJAX发送请求和获取服务端传过来的数据:

<script>

        $(document).ready(function () {
      		function edit_class_modal(ths) {
            	$('#shadow').removeClass('hide');
            	$('#modal_edit').removeClass('hide');
            	var row = $(ths).parent().prevAll();
            	{#console.log(v[0])#}
            	console.log($(row[0]).text());
            	content_title = $(row[0]).text();
            	content_id = $(row[1]).text();
            	$('#edit_title').val(content_title);
            	$('#edit_id').val(content_id);
        	}
            $('#edit_class').click(function () {
                $.ajax({
                    url: '/edit-class/',
                    type: 'GET',
                    data: {
                        'class_id': $('#edit_id').val(),
                        'class_title': $('#edit_title').val()
                    },
                    success: function (data) {
                        if (data == 'ok') {
                            location.href = '/classes/'
                        } else {
                            $('#edit_error').text(data);
                        }
                    }
                })
            })
            $('#close_edit_modal').click(function () {
                $('#shadow').addClass('hide');
                $('#modal_edit').addClass('hide');
            });
        });
    </script>

AJAX编辑班级信息页面:
在这里插入图片描述

14. AJAX删除班级信息

删除班级的逻辑:

def del_class(request):
    '''
    删除班级信息
    '''
    # 获取班级编号,需要通过编号删除班级信息
    class_id = request.GET.get('class_id')
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 将班级id传到sql豫剧中并执行sql
    cursor.execute('delete from class where id=%s', class_id)
    # 提交事务
    conn.commit()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    # 返回操作成功的标识
    return HttpResponse('ok')

AJAX删除班级信息:

<script>
    function del_class(ths) {
        var row = $(ths).parent().prevAll();
        class_id = $(row[1]).text();
        $.ajax({
            url: '/del-class/',
            type: 'get',
            data: {'class_id': class_id},
            success: function (data) {
                if (data == 'ok') {
                    location.href = '/classes/'
                } else {
                    alert('删除失败!')
                }
            }
        })
    }
 </script>
15. 数据库操作代码复用

视图函数操作数据库时有很多重复的操作步骤,可以把这些操作放到一个函数中,

sqlhelper.py

import pymysql

def get_list(sql, args):
    """
    返回查询到的所有结果
    :param sql:
    :param args:
    :return:
    """
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test', charset='utf8')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql
    cursor.execute(sql, args)
    # 获取查询到的内容
    ret = cursor.fetchall()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    return ret

def get_one(sql, args):
    """
    返回查询到的一条结果
    :param sql:
    :param args:
    :return:
    """
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test', charset='utf8')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql
    cursor.execute(sql, args)
    # 获取查询到的内容
    ret = cursor.fetchone()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    return ret

def modify(sql, args):
    """
    修改和删除操作
    :param sql:
    :param args:
    :return:
    """
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test', charset='utf8')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql
    cursor.execute(sql, args)
    # 提交事务
    conn.commit()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
16. AJAX添加学生信息

添加学生信息的业务逻辑:

def add_student_modal(request):
    """
    模态对话框的方式添加班级信息
    :param request:
    :return:
    """
    ret = {'status': True, 'msg': None}
    try:
        name = request.POST.get('name')
        class_id = request.POST.get('class_id')
        if len(name) <= 0 or len(class_id) <= 0:
            ret['status'] = False
            ret['msg'] = '学生姓名或班级不能为空'
            return HttpResponse(json.dumps(ret))
        sqlhelper.modify(sql='insert into student(name,class_id) values(%s,%s)', args=[name, class_id])
    except Exception as e:
        ret['status'] = False
        ret['msg'] = str(e)
    return HttpResponse(json.dumps(ret))

AJAX添加学生信息:

$('#add_student').click(function () {
              $.ajax({
                  url: '/user/add_student_modal/',
                  type: 'POST',
                  data: {
                      'name': $('#name').val(),
                      'class_id': $('#class_id').val()
                  },
                  success: function (data) {
                      data = JSON.parse(data) //把后台传过来的字符串转换成js中的对象
                      if (data.status) {
                          location.href = '/user/student/'
                      } else {
                          $('#add_student_error').text(data.msg);
                      }
                  }
              });
          })

AJAX添加学生信息:
在这里插入图片描述

17. AJAX编辑学生信息

编辑学生信息的业务逻辑:

def edit_student_modal(request):
    """
    模态框编辑学生信息
    :param request: 
    :return: 
    """
    ret = {'status': True, 'msg': None}
    try:
        student_id = request.POST.get('student_id')
        class_id = request.POST.get('class_id_edit')
        student_name = request.POST.get('student_name')
        sqlhelper.modify('update student set name=%s,class_id=%s where id=%s',
                         [student_name, class_id, student_id])
    except Exception as e:
        ret['status'] = False
        ret['msg'] = str(e)
    return HttpResponse(json.dumps(ret))

AJAX编辑学生信息:

function edit_student(ths) {
    //编辑学生信息前的操作
    $('#shadow').removeClass('hide');
    $('#modal_edit_student').removeClass('hide');
    var row = $(ths).parent().prevAll();
    //学生ID
    student_id = $(row[2]).text();
    //学生姓名
    student_name = $(row[1]).text();
    //班级id
    class_id_edit = $(row[0]).attr('cls_id');
    $('#student_name').val(student_name);
    //id不能重复,如果重复,哪个在前找哪个
    $('#class_id_edit').val(class_id_edit);
    $('#student_id').val(student_id);
}
//修改班级信息
$('#edit_student').click(function () {
    $.ajax({
        url: '/user/edit_student_modal/',
        type: 'POST',
        data: {
            'student_id': $('#student_id').val(),
            'student_name': $('#student_name').val(),
            'class_id_edit': $('#class_id_edit').val(),
        },
        success: function (data) {
            data = JSON.parse(data);
            if (data.status) {
                location.reload()
            } else {
                $('#edit_error').text(data.msg);
            }
        }
    })
})

AJAX编辑学生信息页面:
在这里插入图片描述

18. AJAX删除学生信息

删除学生信息的业务逻辑:

def del_student_modal(request):
    """
    模态框删除学生信息
    :param request: 
    :return: 
    """
    ret = {'status': True, 'msg': None}
    try:
        student_id = request.GET.get('student_id')
        sqlhelper.modify('delete from student where id=%s', [student_id, ])
    except Exception as e:
        ret['status'] = False
        ret['msg'] = str(e)
    return HttpResponse(json.dumps(ret))

AJAX删除学生信息:

function del_student(ths) {
    var row = $(ths).parent().prevAll();
    student_id = $(row[2]).text();
    $.ajax({
        url: '/user/del_student_modal/',
        type: 'GET',
        data: {
            'student_id': student_id
        },
        success: function (data) {
            data = JSON.parse(data);
            if (data.status) {
                location.reload()
            } else {
                alert('删除失败!');
            }
        }
    })
}
19. 分页展示学生表

分页后台逻辑:

def student(request):
    '''
    学生信息列表
    :param request:封装了请求相关的所有信息
    :return:返回模板和数据
    '''
    # 创建连接对象
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')
    # 创建游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 查询学生信息列表
    cursor.execute(
        'select student.id,student.name,class_id,class.title from  student left join class on student.class_id=class.id')
    # 获取查询到的所有数据
    student_list = cursor.fetchall()
    paginator = Paginator(student_list, 1)
    current_page = request.GET.get('page')
    try:
        posts = paginator.page(current_page)
    except PageNotAnInteger as e:
        posts = paginator.page(1)
    except EmptyPage as e:
        posts = paginator.page(1)
    # 查询班级信息
    cursor.execute('select id,title from class')
    # 获取查询到的所有班级列表
    class_list = cursor.fetchall()
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    # 返回模板和数据
    return render(request, 'student.html', {'student_list': student_list, 'class_list': class_list, 'posts': posts})

前台分页展示:

<!--学生信息展示-->
<table class="table table-hover text-center" style="background: white;margin-bottom: 0">
    <tr>
        <th class="text-center">ID</th>
        <th class="text-center">学生姓名</th>
        <th class="text-center">学生班级</th>
        <th class="text-center">操作</th>
    </tr>
    {% for row in posts.object_list %}
        <tr>
            <td>{{ row.id }}</td>
            <td>{{ row.name }}</td>
            <td cls_id="{{ row.class_id }}">{{ row.title }}</td>
            {#<td>{{ row.class_id }}</td>#}
            <td>
                <a href="/user/edit_student/?nid={{ row.id }}">编辑(1)</a>
                <a href="javascript:;" onclick="edit_student(this)">编辑(2)</a>
                <a href="/user/del_student/?nid={{ row.id }}">删除(1)</a>
                <a href="javascript:;" onclick="del_student(this)">删除(2)</a>
            </td>
        </tr>
    {% endfor %}
</table>
<!--分页-->
<nav aria-label="Page navigation" class="text-left">
    <ul class="pagination">
        {% if posts.has_previous %}
            <li>
                {#<a href="/user/student?page={{ posts.previous_page_number }}">上一页</a>#}
                <a href="{% url 'student' %}?page={{ posts.previous_page_number }}">上一页</a>
            </li>
        {% endif %}
       
        {% if posts.has_next %}
            <li>
                {#<a href="/user/student?page={{ posts.next_page_number }}">下一页</a>#}
                <a href="{% url 'student' %}?page={{ posts.next_page_number }}">下一页</a>
            </li>
        {% endif %}
    </ul>
</nav>
<!--/学生信息展示-->

分页展示效果图:
在这里插入图片描述
在这里插入图片描述

20. 数据库操作封装

将数据库操作封装在类中,减少了重复的代码,使代码的非常友好的可读性和可维护性的同时,还提高了系统的执行效率:

import pymysql

class SqlHelper:
    def __init__(self):
        self.conn()

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

    def get_list(self, sql, args):
        self.cursor.execute(sql, args)
        result = self.cursor.fetchall()
        return result

    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()

    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()
21. 添加教师信息

后台添加教师信息的业务逻辑:

def add_teacher(request):
    """
    添加教师
    :param request: 
    :return: 
    """
    if request.method == 'GET':
        class_list = sqlhelper.get_list('select id,title from class', [])
        return render(request, 'add_teacher.html', {'class_list': class_list})
    else:
        name = request.POST.get('name')
        obj = sqlhelper.SqlHelper()
        teacher_id = obj.create('insert into teacher(name) values (%s)', [name, ])
        class_ids = request.POST.getlist('class_ids')  # ['1', '8', '9', '10']
        # 多次连接,多次提交
        """
        for class_id in class_ids:
            sqlhelper.modify('insert into teacher2class(teacher_id,class_id) values (%s,%s)', [teacher_id, class_id])        
        """
        # 一次连接,多次提交
        """
        for class_id in class_ids:
            obj.modify('insert into teacher2class(teacher_id,class_id) values (%s,%s)', [teacher_id, class_id])
        obj.close()
        """
        # 一次连接,一次提交
        data_list = []  # [(9, '8'), (9, '9'), (9, '10')]
        for class_id in class_ids:
            data_list.append((teacher_id, class_id))
        obj.multiple_modify('insert into teacher2class(teacher_id,class_id) values (%s,%s)', data_list)
        obj.close()
        return render(request, 'teacher.html')

前台添加教师信息:

...
<form action="/user/add_teacher/" method="post">
    <div class="form-group">
        <label>教师姓名:</label>
        <input type="text" class="form-control" id="" placeholder="请输入教师的姓名" name="name">
    </div>
    <div class="form-group">
        <select multiple class="form-control" name="class_ids">
            {% for row in class_list %}
                <option value="{{ row.id }}">{{ row.title }}</option>
            {% endfor %}
        </select>
    </div>
    <button type="submit" class="btn btn-primary">添加</button>
</form>
...

添加教师信息页面效果:
在这里插入图片描述

22. 查询教师和任课班级信息

查询教师和任课班级信息的业务逻辑:

def teacher(request):
    """
    查询教师和任课班级信息
    :param request:
    :return:
    """
    obj = sqlhelper.SqlHelper()
    teacher_list = obj.get_list(
        'select teacher.id as tid,teacher.name,class.title from teacher left join teacher2class on teacher.id = teacher2class.teacher_id left join class on teacher2class.class_id = class.id ;',
        [])
    """
    print(teacher_list)
    [
    {'tid': 1, 'name': '李娇', 'title': '网络工程'}, 
    {'tid': 1, 'name': '李娇', 'title': '计算机科学与技术'},
    {'tid': 1, 'name': '李娇', 'title': '软件技术'},
    {'tid': 1, 'name': '李娇', 'title': '软件工程'},
    {'tid': 2, 'name': '李晓', 'title': '网络工程'},
    {'tid': 2, 'name': '李晓', 'title': '软件工程'}
    ]
    """
    result = {}
    for row in teacher_list:
        tid = row['tid']
        if tid in result:
            result[tid]['titles'].append(row['title'])
        else:
            result[tid] = {'tid': row['tid'], 'name': row['name'], 'titles': [row['title'], ]}
    """
    print(ret)
    {
        1: {'tid': 1, 'name': '李娇', 'titles': ['网络工程', '计算机科学与技术', '软件技术', '软件工程']}, 
        2: {'tid': 2, 'name': '李晓', 'titles': ['网络工程', '软件工程']}
    }
    """
    return render(request, 'teacher.html', {'teacher_list': result.values()})

前台查询教师和任课班级信息:

...
<table class="table table-hover text-center" style="background: white;margin-bottom: 0">
    <tr>
        <th class="text-center">ID</th>
        <th class="text-center">教师姓名</th>
        <th class="text-center">任教班级</th>
        <th class="text-center">操作</th>
    </tr>
    {% for row in teacher_list %}
        <tr>
            <td>{{ row.tid }}</td>
            <td>{{ row.name }}</td>
            <td>
                {% for item in row.titles %}
                    <span>{{ item }}</span>
                {% endfor %}
            </td>
            <td>
                <a href="/user/edit_teacher/?nid={{ row.tid }}">编辑</a>
                <a href="/user/del_teacher/?nid={{ row.tid }}">删除</a>
            </td>
        </tr>
    {% endfor %}
</table>
...

前台查询教师和任课班级信息的页面效果:
在这里插入图片描述

23. 编辑教师信息

后台编辑教师信息逻辑:

def edit_teacher(request):
    if request.method == 'GET':
        nid = request.GET.get('nid')
        obj = sqlhelper.SqlHelper()
        # 当前教师的信息
        teacher_info = obj.get_one('select id,name from teacher where id = %s', [nid, ])
        # 当前教师的任教班级的id信息
        class_id_list = obj.get_list('select class_id from teacher2class where teacher_id=%s', [nid, ])
        # 所有的班级信息
        class_list = obj.get_list('select id,title from class', [])
        """
        print(teacher_list) # {'id': 2, 'name': '李晓'}
        print(class_list) # [{'id': 1, 'title': '软件工程'}, {'id': 8, 'title': '软件技术'}, {'id': 9, 'title': '计算机科学与技术'}, {'id': 10, 'title': '网络工程'}]
        print(class_id_list) # [{'class_id': 1}, {'class_id': 10}]
        """
        obj.close()
        temp = []
        for item in class_id_list:
            temp.append(item['class_id'])
        """
        print(temp)  # [1, 10]
        """
        return render(request, 'edit_teacher.html',
                      {'class_list': class_list, 'teacher_info': teacher_info, 'class_id_list': temp})
    else:
        # 获取post请求的url上的参数
        nid = request.GET.get('nid')
        print(nid)
        name = request.POST.get('name')
        class_ids = request.POST.getlist('class_ids')  # ['1', '8', '9', '10']
        obj = sqlhelper.SqlHelper()
        obj.modify('update teacher set name = %s where id = %s', [name, nid])
        obj.modify('delete from teacher2class where teacher_id = %s', [nid])
        data_list = []  # [('1', '1'), ('1', '8'), ('1', '9'), ('1', '10')]
        """
        for class_id in class_ids:
            temp = (nid, class_id,)
            data_list.append(temp)
        """
        # 使用lambda表达式
        func = lambda nid, class_id: data_list.append((nid, class_id))
        for class_id in class_ids:
            func(nid, class_id)
        obj.multiple_modify('insert into teacher2class(teacher_id,class_id) values (%s,%s)', data_list)
        return redirect('/user/teacher/')

前台编辑教师信息:

...
<form action="/user/edit_teacher/?nid={{ teacher_info.id }}" method="post">
    <div class="form-group">
        <label>教师姓名:</label>
        <input type="text" class="form-control" id="" placeholder="" name="name"
               value="{{ teacher_info.name }}">
    </div>
    <div class="form-group">
        <select multiple class="form-control" name="class_ids">
            {% for item in class_list %}
                {% if item.id in class_id_list %}
                    <option selected value="{{ item.id }}">{{ item.title }}</option>
                {% else %}
                    <option value="{{ item.id }}">{{ item.title }}</option>
                {% endif %}
            {% endfor %}
        </select>
    </div>
    <button type="submit" class="btn btn-primary">更新</button>
</form>
...

前台编辑教师信息的页面效果:
在这里插入图片描述

24. AJAX删除教师信息

AJAX方式删除教师信息的后台逻辑:

def del_teacher_modal(request):
    """
    AJAX的方式删除教师信息
    :param request: 
    :return: 
    """
    if request.method == 'GET':
        ret = {'status': True, 'msg': None}
        try:
            obj = sqlhelper.SqlHelper()
            tid = request.GET.get('teacher_id')
            obj.modify('delete from teacher where id =%s', [tid])
            obj.modify('delete from teacher2class where teacher_id = %s', [tid])
            obj.close()
        except Exception as e:
            ret['status'] = False
            ret['msg'] = "删除失败!"
        return HttpResponse(json.dumps(ret))

前台的部分代码:

{% for row in teacher_list %}
    <tr>
        <td>{{ row.tid }}</td>
        <td>{{ row.name }}</td>
        <td>
            {% for item in row.titles %}
                <span>{{ item }}</span>
            {% endfor %}
        </td>
        <td>
            <a href="/user/edit_teacher/?nid={{ row.tid }}">编辑</a>
            <a href="javascript:;" class="del_teacher" onclick="del_teacher_modal(this)">删除</a>
        </td>
    </tr>
{% endfor %}
...
<script>
...
//Ajax删除教师信息
function del_teacher_modal(ths) {
    falg = confirm('确定要删除?')
    if (falg) {
        var row = $(ths).parent().prevAll();
        teacher_id = $(row[2]).text();
        $.ajax({
            url: '/user/del_teacher_modal/',
            type: 'get',
            data: {'teacher_id': teacher_id},
            dataType: 'json',
            success: function (arg) {
                if (arg.status) {
                    location.reload()
                } else {
                    alert(arg.msg)
                }
            }
        })
    }
}
...
</script>

前台的效果图:
在这里插入图片描述

25. AJAX添加教师信息

AJAX添加教师信息后台逻辑:

def add_teacher_modal(request):
    """
    AJAX的方式添加教师信息
    :param request: 
    :return: 
    """
    if request.method == 'GET':
        obj = sqlhelper.SqlHelper()
        class_list = obj.get_list('select id,title from class', [])
        import time
        # 这里是用来模拟用户网站压力比较大的情况下
        time.sleep(0.2)
        obj.close()
        return HttpResponse(json.dumps(class_list))
    if request.method == 'POST':
        ret = {'status': True, 'msg': None}
        # 一般ajax请求要加上try
        try:
            name = request.POST.get('name')
            class_ids = request.POST.getlist('class_ids')  # ['1', '8', '9', '10']
            # print(name,class_ids) #奈何 ['9', '10']
            obj = sqlhelper.SqlHelper()
            teacher_id = obj.create('insert into teacher(name) values (%s) ', [name, ])
            data_list = []
            func = lambda item: data_list.append((teacher_id, item))
            for item in class_ids:
                func(item)
            # print(data_list)  # [(8, '8'), (8, '10')]
            obj.multiple_modify('insert teacher2class(teacher_id,class_id) values(%s,%s)', data_list)
            obj.close()
        except Exception as e:
            ret['status'] = False
            ret['msg'] = '处理失败!'
        return HttpResponse(json.dumps(ret))

前台AJAX添加教师信息:

<script>
    $(function () {
        addBtn();
        shadow_btn();
        close_btn();
        add_teacher_modal();
    })

    function shadow_btn() {
        $('#shadow').click(function () {
            $('#shadow,#modal_add_teacher').addClass('hide');
        });
    }

    function close_btn() {
        $('#close_btn').click(function () {
            $('#shadow,#modal_add_teacher').addClass('hide');
        });
    }

    //点击按钮之后如果数据没有拿到就不断动画加载
    function addBtn() {
        $('#addBtn').click(function () {
            $('#shadow').removeClass('hide');
            $('#loading').removeClass('hide');
            $.ajax({
                url: '/user/add_teacher_modal/',
                type: 'get',
                dataType: 'json',//拿到的是对象
                success: function (arg) {
                    //alert(arg)//[object Object],[object Object],[object Object],[object Object]
                    $('#class_ids').html('') //保证上一次的标签内容不会留存再页面上
                    $.each(arg, function (i, row) {
                        var tag = $("<option></option>").html(row.title);
                        tag.attr('value', row.id)
                        $('#class_ids').append(tag)
                    })
                    $('#loading').addClass('hide');
                    $('#modal_add_teacher').removeClass('hide');
                }
            })
        })
    }

    //Ajax添加教师信息
    function add_teacher_modal() {
        $('#addTeacherBtn').click(function () {
            var name = $('#name').val();
            var class_ids = $('#class_ids').val();//['9', '10']
            $.ajax({
                url: '/user/add_teacher_modal/',
                type: 'POST',
                data: {'name': name, 'class_ids': class_ids},
                traditional: true,//如果提交的数据有列表,需要添加这个属性
                dataType: 'json', //如果后台返回的是json格式的数据则这里必须写上json,大小写忽略
                success: function (arg) {
                    if (arg.status) {
                        location.reload();
                    } else {
                        $('#add_teacher_error').text(arg.msg);
                    }
                }
            })
        })
    }
</script>

前台AJAX添加教师信息的页面效果:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章