Django入门到放弃 学习笔记 02

跟b站武沛齐老师的视频学习
对学习过程进行一些记录以便复习 同时自我督促 :D冲鸭

视频链接: 15天django入门到放弃-哔哩哔哩.

回顾

Web框架本质

  • 本质:socket
  • Http协议:头 + 体
  • 字符串

Django

  • 安装
  • django-admin startproject mysite
  • 配置
    • 模板路径
    • 静态文件
    • CSRF注释
  • urls.py
    • url -> 函数
  • 函数
    • def index(request):
        request.method
        request.GET
        request.POST
        
        return HttpResponse(…)
        return render(request, ‘模板路径’, {})
        return redirest(’URL’)
  • 模板渲染
    • def index(request):
        return render(request, ‘模板路径’, {
          ‘k1’: ‘v1’,
          ‘k2’: [1, 2, 3, 4],
          ‘k3’: {‘x’: …},
           })
    • index.html
        <h1>{{ k1 }}</h1>
        <h1>{{ k2.2 }}</h1>
        {% for item in k2%}
          <h1>{{ item }}</h1>
        {% endfor %}
        <h1>{{ k3.x }}</h1>

系统概览

学生管理系统

表:班级 学生 老师
单表操作:增 删 改 查
一对多操作:增 删 改 查
多对多操作:增 删 改 查

数据库表结构设计

表结构:班级\学生\老师
  班级表:
    id title
     1 A班
     2 B班
  学生表:
    id name 班级id(FK)
     1 张三  1
  老师表:
    id name
     1 张老师
     2 李老师
     3 王老师
  老师班级关系表:
    id 老师id 班级id
     1  1    1
     2  1    2
     3  2    2

项目结构完善

  • templates 文件夹,用于存放 html 文件;
  • 新增 static 文件夹,用于存放静态文件;
  • 新增 app01 文件夹,用于存放函数文件。

part1 单表操作

显示班级列表

app01 文件夹下新建 views.py,在 urls.py 中导入 viewsurlpatterns 中添加 path('classes/', views.classes),
编写 classes 函数,连接数据库,读取 idclass,形成 class_list 传给前端:

def classes(request):

    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select id, title from class")
    class_list = cursor.fetchall()
    cursor.close()
    conn.close()
    return render(request, 'classes.html', {'class_list': class_list})

classes.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>classes</title>
</head>
<body>
    <h1>班级列表</h1>
    <table>
        <thead>
        <tr>
            <th>id</th>
            <th>班级名称</th>
        </tr>
        </thead>
        <tbody>
        {% for row in class_list %}
            <tr>
                <td>{{ row.id }}</td>
                <td>{{ row.title }}</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

</body>
</html>

实现增加班级功能

urls.pyurlpatterns 中添加 path('add-class/', views.add_class),
classes.html 中增加“添加”按钮:

<div>
    <a href="/add-class/">添加</a>
</div>

前端一个表单,按下“提交按钮”将输入框内数据传回后端,add_class.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add-class</title>
</head>
<body>
    <h1>添加班级</h1>
    <form method="post" action="/add-class/">   <!--转到add-class路径-->
        <p>班级名称:<input type="text" name="title"></p>    <!--返回数据的键为title-->
        <input type="submit" value="提交">
    </form>
</body>
</html>

编写 add_class 函数,初次来到此处时请求类型为 GET,直接呈现页面;若请求类型为 POST,则连接数据库,将获取到的 title 内容加入数据库,并回到班级列表展示:

def add_class(request):
    if request.method == 'GET':
        return render(request, 'add_class.html')
    else:
        print(request.POST)
        title = request.POST.get('title')

        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute("insert into class(title) values(%s)", title)
        conn.commit()
        cursor.close()
        conn.close()

        return redirect('/classes/')

注意:redirect 和 render 的区别?
redirect url
render html

实现删除班级功能

urls.pyurlpatterns 中添加 path('del-class/', views.del_class),
classes.html 中修改表单,增加“操作”栏,每行数据后添加“删除”按钮,链接到 /del-class/ 并传 id 回后端:

	<table>
        <thead>
        <tr>
            <th>id</th>
            <th>班级名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in class_list %}
            <tr>
                <td>{{ row.id }}</td>
                <td>{{ row.title }}</td>
                <td><a href="/del-class/?nid={{ row.id }}">删除</a></td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

del_class 函数,连接数据库删除 id 对应班级数据:

def del_class(request):
    nid = request.GET.get('nid')

    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("delete from class where id=%s", [nid, ])
    conn.commit()
    cursor.close()
    conn.close()

    return redirect('/classes/')

在用户点击“删除”按钮后,实际上进行了两次传递,首先跳转至 /del-class/ 执行 del_class 删除了班级数据,然后重定位到 /classes/ 执行 classes 重新从数据库获取信息,展示班级列表。

实现编辑班级功能

urls.pyurlpatterns 中添加 path('edit-class/', views.edit_class),
classes.html 中修改表单,每行数据后添加“编辑”按钮,链接到 /edit-class/ 并传 id 回后端:

<td>
	<a href="/edit-class/?nid={{ row.id }}">编辑</a>
	|
	<a href="/del-class/?nid={{ row.id }}">删除</a>
</td>

edit_class.htmladd_class.html 类似,在其基础上,输入框的默认值应为该数据原本的值,另外需要将所修改数据对应的 id 同时传回后端,因此增加一个不可见的 id 输入框来传递 id

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add-class</title>
</head>
<body>
    <h1>编辑班级</h1>
    <form method="post" action="/edit-class/">
        <input style="display: none" value="{{ result.id }}" name="id">
        <p>班级名称:<input type="text" value="{{ result.title }}" name="title"></p>    <!--返回数据的键为title-->
        <input type="submit" value="提交">
    </form>
</body>
</html>

edit_class 函数,仍是分为 GET 和 POST 两种情况:

def edit_class(request):
    if request.method == "GET":
        nid = request.GET.get('nid')

        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        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})

    else:
        nid = request.POST.get('id')
        title = request.POST.get('title')

        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute("update class set title=%s where id=%s", [title, nid, ])
        conn.commit()
        cursor.close()
        conn.close()

        return redirect('/classes/')

另一种传递 id 的方法,是在 url 中进行传递,不再需要隐藏输入框,edit_class.html 中表单修改如下:

<form method="post" action="/edit-class/?nid={{ result.id }}">
	<p>班级名称:<input type="text" value="{{ result.title }}" name="title"></p>    <!--返回数据的键为title-->
	<input type="submit" value="提交">
</form>

edit_class 函数修改:

nid = request.GET.get('nid')
title = request.POST.get('title')

相比之下,第二种方法更为简洁。



教师部分(课后作业)

views.py

def teachers(request):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select id, `name` from teacher")
    teacher_list = cursor.fetchall()
    cursor.close()
    conn.close()

    return render(request, 'teachers.html', {'teacher_list': teacher_list})


def add_teacher(request):
    if request.method == 'GET':
        return render(request, 'add_teacher.html')

    else:
        name = request.POST.get('name')

        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute("insert into teacher(`name`) value(%s)", [name, ])
        conn.commit()
        cursor.close()
        conn.close()

        return redirect('/teachers/')


def del_teacher(request):
    nid = request.GET.get('nid')

    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("delete from teacher where id=%s", [nid, ])
    conn.commit()
    cursor.close()
    conn.close()

    return redirect('/teachers/')


def edit_teacher(request):
    if request.method == 'GET':
        nid = request.GET.get('nid')

        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute("select id, `name` from teacher where id=%s", [nid, ])
        result = cursor.fetchone()
        cursor.close()
        conn.close()

        return render(request, 'edit_teacher.html', {'result': result})

    else:
        nid = request.GET.get('nid')
        name = request.POST.get('name')

        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute("update teacher set `name`=%s where id=%s", [name, nid, ])
        conn.commit()
        cursor.close()
        conn.close()

        return redirect('/teachers/')

teachers.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>teachers</title>
</head>
<body>
    <h1>教师列表</h1>
    <a href="/add-teacher/">添加</a>
    <table>
        <thead>
        <tr>
            <th>id</th>
            <th>教师名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in teacher_list %}
        <tr>
            <td>{{ row.id }}</td>
            <td>{{ row.name }}</td>
            <td>
                <a href="/edit-teacher/?nid={{ row.id }}">编辑</a>
                |
                <a href="/del-teacher/?nid={{ row.id }}">删除</a>
            </td>
        </tr>
        {% endfor %}
        </tbody>
    </table>
</body>
</html>

add_teacher.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add_teacher</title>
</head>
<body>
    <h1>添加教师</h1>
    <form method="post" action="/add-teacher/">
        <p>教师名称:<input type="text" name="name"></p>
        <input type="submit" value="提交">
    </form>
</body>
</html>

edit_teacher.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>edit_teacher</title>
</head>
<body>
    <h1>编辑教师</h1>
    <form method="post" action="/edit-teacher/?nid={{ result.id }}">
        <p>教师名称:<input type="text" value="{{ result.name }}" name="name"></p>
        <input type="submit" value="提交">
    </form>
</body>
</html>

part2 一对多操作

显示学生列表

与班级、教师相比,学生的数据库操作稍复杂一些:

"select student.id, student.`name`, class.title from student left JOIN class on student.class_id=class.id"

增加学生

学生所属班级信息以下拉框形式给用户,所以要将班级信息传给前端,数据库操作:

"select id, title from class"

前端:

<p>
	所属班级:
	<select name="class_id">
		{% for row in class_list %}
		<option value="{{ row.id }}">{{ row.title }}</option>
		{% endfor %}
	</select>
</p>

前端姓名和班级返回给后端,选中班级以 id 形式方便操作,写入数据库的语句:

"select id, title from class"

删除学生

与前面的无区别。

编辑学生

与之前类似,下拉框默认选择之根据当前学生的 class_id 确定,需要增加一个判断语句:

<select name="class_id">
	{% for row in class_list %}
		{% if row.id == student_info.class_id %}
		<option selected value="{{ row.id }}">{{ row.title }}</option>
		{% else %}
		<option value="{{ row.id }}">{{ row.title }}</option>
		{% endif %}
	{% endfor %}
</select>

代码

    path('students/', views.students),
    path('add-student/', views.add_student),
    path('del-student/', views.del_student),
    path('edit-student/', views.edit_student),

由于反复相似操作,可以将常用步骤写成函数,简化代码使结构更清晰。
views.py

from utils import sqlhelper


def students(request):
    """
    学生列表
    :param request: 封装请求相关的所有信息
    :return:
    """
    student_list = sqlhelper.get_list("select student.id, student.`name`, class.title from student left JOIN class on student.class_id=class.id", [])
    return render(request, 'students.html', {'student_list': student_list})


def add_student(request):
    if request.method == 'GET':
        class_list = sqlhelper.get_list("select id, title from class", [])
        return render(request, 'add_student.html', {'class_list': class_list})
    else:
        name = request.POST.get('name')
        class_id = request.POST.get('class_id')
        sqlhelper.modify("insert into student(`name`, class_id) values(%s, %s)", [name, class_id, ])
        return redirect('/students/')


def del_student(request):
    nid = request.GET.get('nid')
    sqlhelper.modify("delete from student where id=%s", [nid, ])
    return redirect('/students/')


def edit_student(request):
    if request.method == 'GET':
        nid = request.GET.get('nid')
        class_list = sqlhelper.get_list("select id, title from class",[])
        student_info = sqlhelper.get_one("select id, name, class_id from student where id=%s", [nid, ])
        return render(request, 'edit_student.html', {'class_list': class_list, 'student_info': student_info})

    else:
        nid = request.GET.get('nid')
        name = request.POST.get('name')
        class_id = request.POST.get('class_id')
        sqlhelper.modify("update student set `name`=%s, class_id=%s where id=%s", [name, class_id, nid, ])
        return redirect('/students/')

sqlhelper.py

import pymysql

def get_list(sql, args):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute(sql, args)
    list = cursor.fetchall()
    cursor.close()
    conn.close()

    return list


def get_one(sql, args):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute(sql, args)
    item = cursor.fetchone()
    cursor.close()
    conn.close()

    return item


def modify(sql, args):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute(sql, args)
    conn.commit()
    cursor.close()
    conn.close()

student.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>students</title>
</head>
<body>
    <h1>学生列表</h1>
    <div>
        <a href="/add-student/">添加</a>
    </div>
    <table>
        <thead>
        <tr>
            <th>id</th>
            <th>学生姓名</th>
            <th>所属班级</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in student_list %}
            <tr>
                <td>{{ row.id }}</td>
                <td>{{ row.name }}</td>
                <td>{{ row.title }}</td>
                <td>
                    <a href="/edit-student/?nid={{ row.id }}">编辑</a>
                    |
                    <a href="/del-student/?nid={{ row.id }}">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

</body>
</html>

add_student.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add-student</title>
</head>
<body>
    <h1>添加学生</h1>
    <form method="post" action="/add-student/">
        <p>学生姓名:<input type="text" name="name"></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>

edit_student.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add-student</title>
</head>
<body>
    <h1>编辑学生</h1>
    <form method="post" action="/edit-student/?nid={{ student_info.id }}">
        <p>学生姓名:<input type="text" name="name" value="{{ student_info.name }}"></p>
        <p>
            所属班级:
            <select name="class_id">
                {% for row in class_list %}
                    {% if row.id == student_info.class_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>

part3 单表操作(对话框)

模态对话框

为区分接下来新开一个文件专门写模态对话框版本——
modal_classes.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>classes</title>
    <style>
        .hide {
            display: none;
        }
        .shadow {
            position: fixed;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            background-color: black;
            opacity: 0.4;
            z-index: 999;
        }
        .modal {
            position: fixed;
            left: 50%;
            top: 50%;
            height: 300px;
            width: 400px;
            background-color: white;
            margin-left: -200px;
            margin-top: -150px;
            z-index: 1000;
        }
    </style>
</head>
<body>
    <h1>班级列表</h1>
    <div>
        <a onclick="showModal();">添加</a>
    </div>

    <table>
        <thead>
        <tr>
            <th>id</th>
            <th>班级名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in class_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 %}
        </tbody>
    </table>

    <div id="shadow" class="shadow hide"></div>
    <div id="modal" class="modal hide">
        <form method="post" action="/modal-add-class/">   <!--转到add-class路径-->
            <p>班级名称:<input type="text" name="title"></p>    <!--返回数据的键为title-->
            <input type="submit" value="提交">
        </form>
    </div>

    <script>
        function showModal() {
            document.getElementById('shadow').classList.remove('hide');
            document.getElementById('modal').classList.remove('hide');
        }
    </script>

</body>
</html>

urls.py

    path('modal-classes/', modalviews.classes),
    path('modal-add-class/', modalviews.add_class),

modalviews.py

def classes(request):
    class_list = sqlhelper.get_list("select id, title from class", [])
    return render(request, 'modal_classes.html', {'class_list': class_list})


def modal_add_class(request):
    title = request.POST.get('title')
    sqlhelper.modify("insert into class(title) values(%s)", [title, ])
    return redirect('/classes/')

Form 表单提交后,页面一定会刷新。比如若修改函数返回值为 HttpResponse('ok'),则页面显示 ‘ok’。

若想要保留原始输入内容,则不能用 Form 表单形式提交。

Ajax

取消表单,将输入信息以 Ajax 返回;
classes.html

    <div id="shadow" class="shadow hide"></div>
    <div id="modal" class="modal hide"><!--转到add-class路径-->
        <p>班级名称:<input type="text" name="title" id="title"></p>    <!--返回数据的键为title-->
        <input type="button" value="提交" onclick="AjaxSend();">
    </div>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.12.4.min.js"></script>
    <script>
        function AjaxSend() {
            $.ajax({
                url: '/modal-add-class/',
                type: 'POST',
                data: {'title': $("#title").val()},
                success: function (data) {
                    //当服务器处理完成智慧,返回数据时,该函数自动调用
                    //data=服务端返回的值
                    console.log(data)
                    if(data == "ok") {
                        alert('添加成功')
                    } else {
                        alert('添加失败')
                    }
                }
            })
        }
    </script>

modalviews.html

def add_class(request):
    title = request.POST.get('title')
    print(title)
    if len(title) > 0:
        sqlhelper.modify("insert into class(title) values(%s)", [title, ])
        return HttpResponse('ok')
    else:
        return HttpResponse('not ok')

因为 Ajax 返回字符串,若想要添加班级成功后跳转刷新 classes/ 页面,直接 return redirect('/classes/') 是不可行的;进行修改——

classes.html

    <div id="modal" class="modal hide"><!--转到add-class路径-->
        <p>班级名称:<input type="text" name="title" id="title"></p>    <!--返回数据的键为title-->
        <input type="button" value="提交" onclick="AjaxSend();">
        <input type="button" value="取消" onclick="cancelModal();">
        <span id="errormessage"></span>
    </div>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.12.4.min.js"></script>
    <script>
        function showModal() {
            document.getElementById('shadow').classList.remove('hide');
            document.getElementById('modal').classList.remove('hide');
        }

        function AjaxSend() {
            $.ajax({
                url: '/modal-add-class/',
                type: 'POST',
                data: {'title': $("#title").val()},
                success: function (data) {
                    //当服务器处理完成智慧,返回数据时,该函数自动调用
                    //data=服务端返回的值
                    console.log(data)
                    if(data == "ok") {
                        location.href="/modal-classes"
                    } else {
                        $('#errormessage').text(data);
                    }
                }
            })
        }

        function cancelModal() {
            document.getElementById('shadow').classList.add('hide');
            document.getElementById('modal').classList.add('hide');
        }
    </script>

使后端能够返回错误信息显示在页面上:
modalviews.py

def add_class(request):
    title = request.POST.get('title')
    print(title)
    if len(title) > 0:
        sqlhelper.modify("insert into class(title) values(%s)", [title, ])
        return HttpResponse('ok')
    else:
        return HttpResponse('标题不能为空')

模态对话框版班级操作(课后作业)

urls.py

    path('modal-classes/', modalviews.classes),
    path('modal-add-class/', modalviews.add_class),
    path('modal-edit-class/', modalviews.edit_class),
    path('modal-delete-class/', modalviews.delete_class),

modalviews.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pymysql
from django.shortcuts import render, redirect, HttpResponse
from utils import sqlhelper


def classes(request):
    class_list = sqlhelper.get_list("select id, title from class", [])
    return render(request, 'modal_classes.html', {'class_list': class_list})


def add_class(request):
    title = request.POST.get('title')
    print(title)
    if len(title) > 0:
        sqlhelper.modify("insert into class(title) values(%s)", [title, ])
        return HttpResponse('ok')
    else:
        return HttpResponse('标题不能为空')


def edit_class(request):
    nid = request.POST.get('nid')
    title = request.POST.get('title')
    print(nid, title)
    if len(title) > 0:
        sqlhelper.modify("update class set title=%s where id=%s", [title, nid, ])
        return HttpResponse('ok')
    else:
        return HttpResponse('标题不能为空')


def delete_class(request):
    nid = request.POST.get('nid')
    if nid != None:
        sqlhelper.modify("delete from class where id=%s", [nid, ])
        return HttpResponse('ok')
    else:
        return HttpResponse('失败')

modal_classes.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>classes</title>
    <style>
        .hide {
            display: none;
        }
        .shadow {
            position: fixed;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            background-color: black;
            opacity: 0.4;
            z-index: 999;
        }
        .modal {
            position: fixed;
            left: 50%;
            top: 50%;
            height: 300px;
            width: 400px;
            background-color: white;
            margin-left: -200px;
            margin-top: -150px;
            z-index: 1000;
        }
    </style>
</head>
<body>
    <h1>班级列表</h1>
    <div>
        <a onclick="showAddModal();">添加</a>
    </div>

    <table>
        <thead>
        <tr>
            <th>id</th>
            <th>班级名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in class_list %}
            <tr>
                <td>{{ row.id }}</td>
                <td>{{ row.title }}</td>
                <td>
                    <a onclick="showEditModal({{ row.id }}, '{{ row.title }}');">编辑</a>
                    |
                    <a onclick="AjaxDelete({{ row.id }});">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

    <div id="shadow" class="shadow hide"></div>
    <div id="add-modal" class="modal hide"><!--转到add-class路径-->
        <p>班级名称:<input type="text" name="title" id="add-title"></p>    <!--返回数据的键为title-->
        <input type="button" value="提交" onclick="AjaxSend();">
        <input type="button" value="取消" onclick="cancelAddModal();">
        <span id="add-errormessage"></span>
    </div>
    <div id="edit-modal" class="modal hide">
        <input id="this-id" value="">
        <p>班级名称:<input type="text" name="title" id="edit-title"></p>    <!--返回数据的键为title-->
        <input type="button" value="提交" onclick="AjaxEdit();">
        <input type="button" value="取消" onclick="cancelEditModal();">
        <span id="edit-errormessage"></span>
    </div>


    <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.12.4.min.js"></script>
    <script>
        function showAddModal() {
            document.getElementById('shadow').classList.remove('hide');
            document.getElementById('add-modal').classList.remove('hide');
            $('#add-errormessage').text('');
        }

        function AjaxSend() {
            $.ajax({
                url: '/modal-add-class/',
                type: 'POST',
                data: {'title': $("#add-title").val()},
                success: function (data) {
                    //当服务器处理完成智慧,返回数据时,该函数自动调用
                    //data=服务端返回的值
                    console.log(data)
                    if(data == "ok") {
                        location.href="/modal-classes/"
                    } else {
                        $('#add-errormessage').text(data);
                    }
                }
            })
        }

        function cancelAddModal() {
            document.getElementById('shadow').classList.add('hide');
            document.getElementById('add-modal').classList.add('hide');
        }

        function showEditModal(nid, title) {
            document.getElementById('shadow').classList.remove('hide');
            document.getElementById('edit-modal').classList.remove('hide');
            document.getElementById('edit-title').value = title;
            document.getElementById('this-id').value = nid;
            $('#edit-errormessage').text('');
        }

        function AjaxEdit(nid) {
            console.log($('#this-id').val())
            $.ajax({
                url: '/modal-edit-class/',
                type: 'POST',
                data: {'nid': $('#this-id').val(), 'title': $('#edit-title').val()},
                success: function (data) {
                    console.log(data)
                    if(data == "ok") {
                        location.href="/modal-classes/"
                    } else {
                        $('#edit-errormessage').text(data);
                    }
                }
            })
        }

        function cancelEditModal() {
            document.getElementById('shadow').classList.add('hide');
            document.getElementById('edit-modal').classList.add('hide');
        }

        function AjaxDelete(nid) {
            $.ajax({
                url: '/modal-delete-class/',
                type: 'POST',
                data: {'nid': nid},
                success: function (data) {
                    if (data == 'ok') {
                        location.href = '/modal-classes/'
                    }else {
                        alert('失败')
                    }
                }
            })
        }


    </script>

</body>3
</html>

作业修改

使默认事件不执行:(增加 return)

<a href="www.baidu.com" onclick = "return modelEdit();">对话框编辑</a>

<script>
	function modalEdit() {
		alert(123);
		return false;
	}
</script>

编辑对话框:

<script>
	function modalEdit(ths) {
		document.getElementById('shadow').classList.remove('hide');
		document.getElementById('editModal').classList.remove('hide');
		/*
		1. 获取当前点击标签
		2. 当前标签父亲标签,再找其上方标签
		3. 获取当前行班级名称,赋值到编辑对话框
		*/
		var row = $(ths).parent().prevAll();
		var content = $(row[0]).text();
		$('#editTitle').val(content);
	
		var contentId = $(row[1]).text();
		$('#editId').val(contentId);
</script>

修改函数:

def modal_edit_class(request):
	ret = {'status': True, 'message': None}
	try:
		nid = request.POST.get('nid')
		content = request.POST.get('content')
		sqlhelper.modify("update class set title=%s where id=%s", [content, nid, ])
	except Exception as e:
		ret['status'] = False
		ret['message'] = "处理异常"
	import json
	return HttpResponse(json.dumps(ret))

前端拿到数据的转换操作:

<script>
	...
	success:function(arg) {
		// arg 字符串类型
		// JSON.parse(字符串) => 对象
		// JSON.stringfy(对象) => 字符串
		arg = JSON.parse(arg);
		if (arg.status) {
			location.reload(); // 当前页面刷新
		} else {
			alert(arg.message);
		}
	}
</script>

小结

  • 模态对话框
      Form 表单提交,页面会刷新
  • Ajax
      jQuery

      $.ajax({
        url: ‘要提交的地址’,
        type: ‘POST’, // 或 ‘GET’
        data: {‘k1’: ‘v1’, ‘k2’: $(’#v2’).val()}, // 提交的数据
        success: function(data) {
          // 当服务端处理完毕后,自动执行的回调函数
          // data是返回的数据
        }
      })
  • 其他
      1. 模板语言 if 条件语句
      2. Form 表单提交,页面刷新
      3. Ajax 提交,页面不刷新
      4. js实现页面跳转:location.href = “跳转地址”
      5. 两种方式
        模态对话框(Ajax)如:登录
          - 少量的输入框、下拉框
          - 数据少
        新URL方式 如:博客
          - 操作多
          - 数据大

part3 一对多操作(对话框)

内容概览

  1. 对话框 单表、一对多
  2. 多对多
  3. Bootstrap
  4. fontawesome

JS绑定JQuery绑定

增加学生

使用 jQuery 绑定,设置添加按钮的 id

	<div>
        <a id="addModal">添加</a>
    </div>

对话框:

    <div id="addModal" class="modal hide">
        <h3>增加学生信息</h3>
        <p>姓名:<input id="addName" type="text" name="name" placeholder="姓名"></p>
        <p>班级:
            <select id="addClassId">
                {% for row in class_list %}
                <option value="{{ row.id }}">{{ row.title }}</option>
                {% endfor %}
            </select>
        </p>
        <input id="btnAdd" type="button" value="提交">
        <input type="button" value="取消">
        <span id="addError" style="color: #ff0000"></span>
    </div>

绑定事件:

    <script>
    
        $(function () {
            $('#addModal').click(function () {
                $('#shadow, #addModal').removeClass('hide');
            });
            $('#btnAdd').on("click", function () {
                console.log('ok')
                $.ajax({
                    url: '/modal-add-student/',
                    type: 'POST',
                    data: {'name': $('#addName').val(), 'class_id': $('#addClassId').val()},
                    success: function (arg) {
                        console.log(arg)
                        arg = JSON.parse(arg)
                        if (arg.status) {
                            location.reload()
                        } else {
                            $('#addError').text(arg.message)
                        }
                    }
                })
            });
        });

    </script>

编辑学生

另一种方式进行绑定(因为有多个,如果用 id 查找后面的会找不到):

<a class="btn-edit">编辑</a>

<script>
	$('.btn-edit').click(function () {
    	$('#shadow, #editModal').removeClass('hide');
	});
</script>

编辑学生如何保存 id
增加一行隐藏的 input 栏存放 id

<input id="editId" type="text" style="display: none">

编辑学生如何获取 class_id
一种方法是加一列隐藏的 <td> 存放 class_id,另一种方式是为 class_title 增加自定义属性,值设为 class_id

<td>{{ row.id }}</td>
<td>{{ row.name }}</td>
<td clsId="{{ row.class_id }}">{{ row.title }}</td>

<script>
		...
			$('.btn-edit').click(function () {
                $('#shadow, #editModal').removeClass('hide');
                /*
                1. 获取当前标签 $(this)
                 */
                var tds = $(this).parent().prevAll();
                var studentId = $(tds[2]).text();
                var studentName = $(tds[1]).text();
                console.log(studentName);
                var classId = $(tds[0]).attr('clsId');
                console.log(studentId, studentName, classId);

                $('#editId').val(studentId);
                $('#editName').val(studentName);
                $('#editClassId').val(classId);
            });
</script>

通过属性进行绑定,则此处 $(this) 表示当前标签。

<script>
	dataType: 'JSON', // 方法1
	success: function (arg) {
		JSON.parse(arg) // 方法2
</script>

删除学生

代码

urls.py

    path('modal-students/', modalviews.students),
    path('modal-add-student/', modalviews.add_student),
    path('modal-edit-student/', modalviews.edit_student),
    path('modal-delete-student/', modalviews.delete_student),

modalviews.py

def students(request):
    student_list = sqlhelper.get_list("select student.id, student.`name`, student.class_id, class.title from student LEFT JOIN class on student.class_id=class.id", [])
    class_list = sqlhelper.get_list("select id, title from class", [])

    return render(request, 'modal_students.html', {'student_list': student_list, 'class_list': class_list})


def add_student(request):
    ret = {'status': True, 'message': None}
    try:
        name = request.POST.get('name')
        class_id = request.POST.get('class_id')
        sqlhelper.modify("insert into student(name, class_id) values(%s, %s)", [name, class_id])
    except Exception as e:
        ret['status'] = False
        ret['message'] = str(e)

    return HttpResponse(json.dumps(ret))

def edit_student(request):
    ret = {'status': True, 'message': None}
    try:
        nid = request.POST.get('nid')
        name = request.POST.get('name')
        class_id = request.POST.get('class_id')
        sqlhelper.modify("update student set `name`=%s, class_id=%s where id=%s", [name, class_id, nid, ])
    except Exception as e:
        ret['status'] = False
        ret['message'] = str(e)

    return HttpResponse(json.dumps(ret))


def delete_student(request):
    ret = {'status': True, 'message': None}
    try:
        nid = request.POST.get('nid')
        sqlhelper.modify("delete from student where id=%s", [nid, ])
    except Exception as e:
        ret['status'] = False
        ret['message'] = str(e)

    return HttpResponse(json.dumps(ret))

modal_students.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>students</title>
    <style>
        .hide {
            display: none;
        }
        .shadow {
            position: fixed;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            background-color: black;
            opacity: 0.4;
            z-index: 999;
        }
        .modal {
            position: fixed;
            left: 50%;
            top: 50%;
            height: 300px;
            width: 400px;
            background-color: white;
            margin-left: -200px;
            margin-top: -150px;
            z-index: 1000;
        }
    </style>
</head>
<body>
    <h1>学生列表</h1>
    <div>
        <a id="btn-add">添加</a>
    </div>
    <table>
        <thead>
        <tr>
            <th>id</th>
            <th>学生姓名</th>
            <th>所属班级</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in student_list %}
            <tr>
                <td>{{ row.id }}</td>
                <td>{{ row.name }}</td>
                <td clsId="{{ row.class_id }}">{{ row.title }}</td>
                <td>
                    <a class="btn-edit">编辑</a>
                    |
                    <a class="btn-delete">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

    <div id="shadow" class="shadow hide"></div>
    <div id="addModal" class="modal hide">
        <h3>增加学生信息</h3>
        <p>姓名:<input id="addName" type="text" name="name" placeholder="姓名"></p>
        <p>班级:
            <select id="addClassId">
                {% for row in class_list %}
                <option value="{{ row.id }}">{{ row.title }}</option>
                {% endfor %}
            </select>
        </p>
        <input id="btnAdd" type="button" value="提交">
        <input id="quitAdd" type="button" value="取消">
        <span id="addError" style="color: #ff0000"></span>
    </div>
    <div id="editModal" class="modal hide">
        <h3>编辑学生信息</h3>
        <input id="editId" type="text" style="display: none">
        <p>姓名:<input id="editName" type="text" name="name" placeholder="姓名"></p>
        <p>班级:
            <select id="editClassId">
                {% for row in class_list %}
                <option value="{{ row.id }}">{{ row.title }}</option>
                {% endfor %}
            </select>
        </p>
        <input id="btnEdit" type="button" value="提交">
        <input id="quitEdit" type="button" value="取消">
        <span id="editError" style="color: #ff0000"></span>
    </div>

    <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.12.4.min.js"></script>
    <script>

        $(function () {
            $('#btn-add').click(function () {
                $('#shadow, #addModal').removeClass('hide');
                $('#addError').text('')
            });

            $('#btnAdd').on("click", function () {
                console.log('ok')
                $.ajax({
                    url: '/modal-add-student/',
                    type: 'POST',
                    data: {'name': $('#addName').val(), 'class_id': $('#addClassId').val()},
                    success: function (arg) {
                        console.log(arg)
                        arg = JSON.parse(arg)
                        if (arg.status) {
                            location.reload()
                        } else {
                            $('#addError').text(arg.message)
                        }
                    }
                })
            });

            $('#quitAdd').click(function () {
                $('#shadow, #addModal').addClass('hide');
            })

            $('.btn-edit').click(function () {
                $('#shadow, #editModal').removeClass('hide');
                $('#editError').text('')
                /*
                1. 获取当前标签 $(this)
                 */
                var tds = $(this).parent().prevAll();
                var studentId = $(tds[2]).text();
                var studentName = $(tds[1]).text();
                console.log(studentName);
                var classId = $(tds[0]).attr('clsId');
                console.log('id:', studentId, 'name:', studentName, 'class_id:', classId);

                $('#editId').val(studentId);
                $('#editName').val(studentName);
                $('#editClassId').val(classId);
                console.log('nid:', $('#editId').val(), 'name:', $('#editName').val(), 'class_id:', $('#editClassId').val())
            });

            $('#btnEdit').click(function () {
                $.ajax({
                    url: '/modal-edit-student/',
                    type: 'POST',
                    data: {'nid': $('#editId').val(), 'name': $('#editName').val(), 'class_id': $('#editClassId').val()},
                    dataType: 'JSON', // 方法1
                    success: function (arg) {
                         //JSON.parse(arg) // 方法2
                        if (arg.status) {
                            location.reload();
                        } else {
                            $('#editError').text(arg.message);
                        }
                    }
                })
            });

            $('#quitEdit').click(function () {
                $('#shadow, #editModal').addClass('hide');
            })

            $('.btn-delete').click(function () {
                var tds = $(this).parent().prevAll();
                var nid = $(tds[2]).text();
                $.ajax({
                    url: '/modal-delete-student/',
                    type: 'POST',
                    data: {'nid': nid},
                    dataType: 'JSON',
                    success: function (arg) {
                        if (arg.status) {
                            location.reload();
                        } else {
                            alert(arg.message);
                        }
                    }
                })
            })
        });

    </script>

</body>
</html>

part4 多对多操作

显示教师列表

数据库操作:

select teacher.id as tid, teacher.`name`, class.title from teacher
LEFT JOIN teacher2class on teacher2class.teacher_id=teacher.id
LEFT JOIN class on class.id=teacher2class.class_id;

这样获取到的数据(字典)是这样的:

[{'tid': 1, 'name': '张老师', 'title': 'C班'},
 {'tid': 1, 'name': '张老师', 'title': 'B班'},
 {'tid': 2, 'name': '李老师', 'title': 'D班'}, 
 {'tid': 2, 'name': '李老师', 'title': 'A班'}, 
 {'tid': 3, 'name': '王老师', 'title': 'C班'}, 
 {'tid': 3, 'name': '王老师', 'title': 'B班'}, 
 {'tid': 3, 'name': '王老师', 'title': 'A班'}]

我们需要将其整合:

	result = {
        # 1: {'name': xxx, 'tid': 1, 'titles': ['xxx', 'xxx']},
    }
    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']]}

这样得到的数据就变成:

[1: {'tid': 1, 'name': '张老师', 'titles': ['C班', 'B班']},
 2: {'tid': 2, 'name': '李老师', 'titles': ['D班', 'A班']}, 
 3: {'tid': 3, 'name': '王老师', 'titles': ['C班', 'B班', 'A班']}]

前端的任课班级一栏再增加一个循环进行显示:

    <table border="1">
        <thead>
        <tr>
            <th>id</th>
            <th>教师姓名</th>
            <th>任课班级</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in teacher_list %}
        <tr>
            <td>{{ row.tid }}</td>
            <td>{{ row.name }}</td>
            <td>
                {% for item in row.titles %}
                    <span style="display: inline-block; padding: 5px; border: 1px solid cadetblue;">{{ item }}</span>
                {% endfor %}
            </td>
            <td>
                <a>编辑</a>
                |
                <a>删除</a>
            </td>
        </tr>
        {% endfor %}
        </tbody>
    </table>

增加教师

采用 url 跳转的方式。一个教师可以教授多个班级,所以使用复选框:

<body>
    <h1>添加教师</h1>
    <form method="post" action="/add-teacher/">
        <p>教师名称:<input type="text" name="name"></p>
        <p>任教班级:
            <select multiple size="5" name="class_ids">
                {% for item in class_list %}
                <option value="{{ item.id }}">{{ item.title }}</option>
                {% endfor %}
            </select>
        </p>
        <input type="submit" value="提交">
    </form>
</body>

后台以 getlist 的方式获取 class_ids 列表:

class_ids = request.POST.getlist('class_ids')

增加教师信息需要改动两个表—— teacher 表和 teaccher2class 表。先在老师表中添加一条数据,再在老师班级关系表中插入数据,因此需要获取新增老师的 id,考虑增加一种具有返回值的 sqlhelper 函数:

def create(sql, args):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute(sql, args)
    conn.commit()
    last_row_id = cursor.lastrowid
    cursor.close()
    conn.close()
    
    return last_row_id

插入数据时,若采用循环方式,如:

for class_id in class_ids:
	sqlhelper.modify("insert into teacher2class(teacher_id, class_id) values(%s, %s)", [teacher_id, class_id])

会反复连接、提交和关闭数据库,十分耗时。因此对 sqlhelper 进行修改。设置一个 SqlHelper 类,以类的方式,对公共的操作进行封装:

class SqlHelper(object):

    def __init__(self):
        # 读取配置文件
        self.connect()

    @staticmethod
    def connect(self):
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='db_test')  # 可以以配置文件方式
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

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

    def get_one(self, sql, args):
        self.cursor.execute(sql, args)
        item = self.cursor.fetchone()
        return item

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

这样就可以一次性提交数据:

		data_list = []
        for class_id in class_ids:
            temp = (teacher_id, class_id)
            data_list.append(temp)
        obj = sqlhelper.SqlHelper()
        obj.multiple_modify("insert into teacher2class(teacher_id, class_id) values (%s, %s)", data_list)
        obj.close()

编辑教师

与 url 跳转方式编辑学生相似。在任教班级的默认显示上,需要将获取到的 class_id_list 中对应的班级设为选中,而通过

class_id_list = obj.get_list("select teacher_id, class_id from teacher2class where teacher_id=%s", [nid, ])

获取到的数据形式为:

[{'class_id': 1}, {'class_id': 4}]

为了方便需要将其转换形式:

        temp = []
        for i in class_id_list:
            temp.append(i['class_id'])
        print(temp)

这样得到的数据形式为:

[1, 4]

在 html 中利用循环将列表中 id 对应的班级设为 selected 即可。

更新老师班级关系表时有两种方法:·

  1. 删除该老师原来任教的所有班级数据,再将新数据写入。这种方法简单,但效率较低;
  2. 将新数据与原来的进行匹配,然后进行增加和删除。这种方法效率更高。

代码

views.py

def teachers(request):
    teacher_list = sqlhelper.get_list('''
    select teacher.id as tid, teacher.`name`, class.title from teacher
    LEFT JOIN teacher2class on teacher2class.teacher_id=teacher.id
    LEFT JOIN class on class.id=teacher2class.class_id;
    ''', [])
    print(teacher_list)

    result = {
        # 1: {'name': xxx, 'tid': 1, 'titles': ['xxx', 'xxx']},
    }
    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(result.values())

    return render(request, 'teachers.html', {'teacher_list': result.values()})


def add_teacher(request):
    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')
        class_ids = request.POST.getlist('class_ids')
        print(name, class_ids)
        # 在老师表中添加一条数据
        teacher_id = sqlhelper.create("insert into teacher(`name`) values(%s)", [name,])
        # 在老师班级关系表中插入数据
        # 首先调整数据形式
        data_list = [
            # (1, 1)
        ]
        # 一次性提交数据
        for class_id in class_ids:
            temp = (teacher_id, class_id)
            data_list.append(temp)
        obj = sqlhelper.SqlHelper()
        obj.multiple_modify("insert into teacher2class(teacher_id, class_id) values (%s, %s)", data_list)
        obj.close()

        return redirect('/teachers/')


def edit_teacher(request):
    if request.method == 'GET':
        nid = request.GET.get('nid')
        obj = sqlhelper.SqlHelper()
        print(nid)
        teacher_info = obj.get_one("select id, `name` from teacher where id=%s", [nid, ])
        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", [])
        obj.close()
        print(teacher_info, class_id_list)
        temp = []
        for i in class_id_list:
            temp.append(i['class_id'])
        print(temp)

        return render(request, 'edit_teacher.html', {
            'teacher_info': teacher_info,
            'class_id_list': temp,
            'class_list': class_list
        })

    else:
        nid = request.GET.get('nid')
        name = request.POST.get('name')
        class_ids = request.POST.getlist('class_ids')
        print(nid, name, class_ids)
        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 = []
        for class_id in class_ids:
            temp = (nid, class_id)
            data_list.append(temp)
        print(data_list)
        obj.multiple_modify("insert into teacher2class(teacher_id, class_id) values(%s, %s)", data_list)
        obj.close()

        return redirect('/teachers/')


def delete_teacher(request):
    nid = request.GET.get('nid')
    obj = sqlhelper.SqlHelper()
    obj.modify("delete from teacher where id=%s", [nid, ])
    obj.modify("delete from teacher2class where teacher_id=%s", [nid, ])
    return redirect('/teachers/')

teachers.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>teachers</title>
</head>
<body>
    <h1>教师列表</h1>
    <a href="/add-teacher/">添加</a>
    <table border="1">
        <thead>
        <tr>
            <th>id</th>
            <th>教师姓名</th>
            <th>任教班级</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in teacher_list %}
        <tr>
            <td>{{ row.tid }}</td>
            <td>{{ row.name }}</td>
            <td>
                {% for item in row.titles %}
                    <span style="display: inline-block; padding: 5px; border: 1px solid cadetblue;">{{ item }}</span>
                {% endfor %}
            </td>
            <td>
                <a href="/edit-teacher/?nid={{ row.tid }}">编辑</a>
                |
                <a href="/delete-teacher/?nid={{ row.tid }}">删除</a>
            </td>
        </tr>
        {% endfor %}
        </tbody>
    </table>
</body>
</html>

add_teacher.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add-teacher</title>
</head>
<body>
    <h1>添加教师</h1>
    <form method="post" action="/add-teacher/">
        <p>教师名称:<input type="text" name="name"></p>
        <p>任教班级:
            <select multiple size="5" name="class_ids">
                {% for item in class_list %}
                <option value="{{ item.id }}">{{ item.title }}</option>
                {% endfor %}
            </select>
        </p>
        <input type="submit" value="提交">
    </form>
</body>
</html>

edit_teacher.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>edit-teacher</title>
</head>
<body>
    <h1>编辑教师</h1>
    <form method="post" action="/edit-teacher/?nid={{ teacher_info.id }}">
        <p>教师名称:<input type="text" value="{{ teacher_info.name }}" name="name"></p>
        <p>任教班级:
            <select multiple size="5" name="class_ids">
                {% for item in class_list %}
                    {% if item.id in class_id_list %}
                        <option value="{{ item.id }}" selected>{{ item.title }}</option>
                    {% else %}
                        <option value="{{ item.id }}">{{ item.title }}</option>
                    {% endif %}
                {% endfor %}
            </select>
        </p>
        <input type="submit" value="提交">
    </form>
</body>
</html>

小结

  1. Http 请求生命周期
     请求头 -> 提取 URL -> 路由关系匹配 -> 函数(模板 + 渲染) -> 返回用户(响应头 + 响应体)

  2. render 会对页面进行渲染,即替换。

  3. 模板的渲染是在后台执行的。

一个例子:
后端:

def function(request):
   render(request, 'example.html', {'k1': 1, 'k2': 'uuu'})

前端:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
</head>
<body>
   <h1>{{ k1 }}</h1>
   <h1>{{ k2 }}</h1>

   <script>
       alert();
   </script>
</body>
</html>

若是 alert({{ k1 }});,则页面弹出警告框,内容为 “1”;
若是 alert({{ k2 }});,则会出现报错,uuu is not defined。因为经过替换后代码变为 alert(uuu);,而 uuu 并没有定义。因此若想要警告框显示 “uuu”,应该写成 alert('{{ k2 }}');

  1. HTML
     for
     if
     索引
     {{ }}
  2. js 序列化 & 反序列化
  3. 阻止默认事件发生:
     onclick 事件绑定: <a οnclick=‘return func();’></a> 同时函数里 return false;
     jQuery 方式绑定: <a id></a> 函数里 return false;

part5 多对多操作(对话框)

增加教师

为了避免函数直接写在一起太凌乱,可以如下进行绑定:

    <script>
        $(function () {
            bindAdd();
        });

        function bindAdd() {
        ...
        }
    </script>

点击“添加”按钮后,向后端获取 class_list 来显示。动态添加方法:

<script>
			...
				$.ajax({
                    url: '/get-all-class/',
                    type: 'GET',
                    dataType: 'JSON',
                    success: function (arg) {
                        console.log(arg)
                        /*
                        0: {id: 1, title: "A班"}
                        1: {id: 2, title: "B班"}
                        2: {id: 3, title: "C班"}
                        3: {id: 4, title: "D班"}
                         */
                        $.each(arg, function (i, row) {
                            var tag = document.createElement('option');
                            tag.innerText = row.title;
                            tag.setAttribute('value', row.id);
                            $('#addClassIds').append(tag);
                        })
                    }
                })
</script>

对于需要时间加载数据的功能,为了更好的用户体验,可以先显示一个加载符号,当后端数据传送过来之后再显示对话框:

	<style>	
        .loading {
            position: fixed;
            width: 200px;
            height: 150px;
            left: 50%;
            top: 50%;
            margin-left: -200px;
            margin-top: -100px;
            background-image: url("/static/images/loading.gif");
            z-index: 10001;
        }
	</style>

	<div id="loading" class="loading hide"></div>

<script>
$('#shadow, #loading').removeClass('hide');
...
$('#loading').addClass('hide');
$('#addModal').removeClass('hide');
</script>

注意,当 ajax 向后端传递数据为列表形式时,需要加上 traditional: true,

编辑教师

在 python 中可以直接用 in 判断一个数据是否在列表中,而在 JavaScript 中,可以通过 indexOf

v = [11, 22, 33]
v.indexOf(22) = 1
v.indexOf(222) = -1

若返回 -1,则代表不存在。

代码

modalviews.py

def teachers(request):
    teacher_list = sqlhelper.get_list('''
    select teacher.id as tid, teacher.`name`, class.title from teacher
    LEFT JOIN teacher2class on teacher2class.teacher_id=teacher.id
    LEFT JOIN class on class.id=teacher2class.class_id;
    ''', [])
    print(teacher_list)

    result = {
        # 1: {'name': xxx, 'tid': 1, 'titles': ['xxx', 'xxx']},
    }
    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(result.values())

    return render(request, 'modal_teachers.html', {'teacher_list': result.values()})


def add_teacher(request):
    ret = {'status': True, 'message': None}
    try:
        name = request.POST.get('name')
        class_id_list = request.POST.getlist('class_id_list')
        obj = sqlhelper.SqlHelper()
        teacher_id = obj.create("insert into teacher(`name`) values(%s)", [name, ])
        data_list = []
        for class_id in class_id_list:
            temp = (teacher_id, class_id)
            data_list.append(temp)
        obj.multiple_modify("insert into teacher2class(teacher_id, class_id) values(%s, %s)", data_list)
        obj.close()
    except Exception as e:
        ret['status'] = False
        ret['message'] = str(e)
    return HttpResponse(json.dumps(ret))


def delete_teacher(request):
    ret = {'status': True, 'message': None}
    try:
        nid = request.POST.get('nid')
        obj = sqlhelper.SqlHelper()
        obj.modify("delete from teacher where id=%s", [nid, ])
        obj.modify("delete from teacher2class where teacher_id=%s", [nid, ])
        obj.close()
    except Exception as e:
        ret['status'] = False
        ret['message'] = str(e)
    return HttpResponse(json.dumps(ret))


def edit_teacher(request):
    ret = {'status': True, 'message': None}
    try:
        nid = request.POST.get('tid')
        name = request.POST.get('name')
        class_ids = request.POST.getlist('class_id_list')
        print('class_id_list', class_ids)
        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 = []
        for class_id in class_ids:
            temp = (nid, class_id)
            data_list.append(temp)
        obj.multiple_modify("insert into teacher2class(teacher_id, class_id) values(%s, %s)", data_list)
        obj.close()
    except Exception as e:
        ret['status'] = False
        ret['message'] = str(e)
    return HttpResponse(json.dumps(ret))


# utils 部分


def get_all_class_and_selected(request):
    nid = request.POST.get('nid')
    obj = sqlhelper.SqlHelper()
    class_list = obj.get_list("select id, title from class", [])
    class_id_list = obj.get_list("select class_id from teacher2class where teacher_id=%s", [nid, ])
    obj.close()
    class_ids = []
    for i in class_id_list:
        class_ids.append(i['class_id'])
    result = [class_list, class_ids]
    print(result)

    return HttpResponse(json.dumps(result))

modal_teachers.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>teachers</title>
    <style>
        .hide {
            display: none;
        }
        .shadow {
            position: fixed;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            background-color: black;
            opacity: 0.4;
            z-index: 999;
        }
        .loading {
            position: fixed;
            width: 200px;
            height: 150px;
            left: 50%;
            top: 50%;
            margin-left: -200px;
            margin-top: -100px;
            background-image: url("/static/images/loading.gif");
            z-index: 10001;
        }
        .modal {
            position: fixed;
            left: 50%;
            top: 50%;
            height: 300px;
            width: 300px;
            background-color: white;
            margin-left: -200px;
            margin-top: -150px;
            z-index: 1000;
        }
    </style>
</head>
<body>
    <h1>教师列表</h1>
    <a id="btn-add">添加</a>
    <table border="1">
        <thead>
        <tr>
            <th>id</th>
            <th>教师姓名</th>
            <th>任课班级</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in teacher_list %}
        <tr>
            <td>{{ row.tid }}</td>
            <td>{{ row.name }}</td>
            <td>
                {% for item in row.titles %}
                    <span style="display: inline-block; padding: 5px; border: 1px solid cadetblue;">{{ item }}</span>
                {% endfor %}
            </td>
            <td>
                <a class="btn-edit">编辑</a>
                |
                <a class="btn-delete">删除</a>
            </td>
        </tr>
        {% endfor %}
        </tbody>
    </table>

    <div id="shadow" class="shadow hide"></div>
    <div id="loading" class="loading hide"></div>
    <div id="addModal" class="modal hide">
        <h3>增加教师信息</h3>
        <p>教师姓名:<input id="addName" type="text" name="name" placeholder="姓名"></p>
        <p>任教班级:
            <select id="addClassIds" multiple size="5"></select>
        </p>
        <input id="btnAdd" type="button" value="提交">
        <input id="quitAdd" type="button" value="取消">
        <span id="addError" style="color: #ff0000"></span>
    </div>
    <div id="editModal" class="modal hide">
        <h3>编辑教师信息</h3>
        <input id="edit_tid" value="" type="hidden">
        <p>教师姓名:<input id="editName" type="text" name="name"></p>
        <p>任教班级:
            <select id="editClassIds" multiple size="5"></select>
        </p>
        <input id="btnEdit" type="button" value="提交">
        <input id="quitEdit" type="button" value="取消">
        <span id="editError" style="color: #ff0000"></span>
    </div>

    <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.12.4.min.js"></script>
    <script>
        $(function () {
            bindAdd();
            bindAddSubmit();
            bindDelete();
            bindEdit();
            bindEditSubmit();
            bindQuit();
        });

        function bindAdd() {
            $('#btn-add').click(function () {
                console.log('ok');
                $('#shadow, #loading').removeClass('hide');
                $('#addClassIds').empty();
                $.ajax({
                    url: '/get-all-class/',
                    type: 'GET',
                    dataType: 'JSON',
                    success: function (arg) {
                        console.log(arg);
                        /*
                        0: {id: 1, title: "A班"}
                        1: {id: 2, title: "B班"}
                        2: {id: 3, title: "C班"}
                        3: {id: 4, title: "D班"}
                         */
                        $.each(arg, function (i, row) {
                            var tag = document.createElement('option');
                            tag.innerText = row.title;
                            tag.setAttribute('value', row.id);
                            $('#addClassIds').append(tag);
                        });
                        $('#loading').addClass('hide');
                        $('#addModal').removeClass('hide');
                    }
                });
            });
        }

        function bindAddSubmit() {
            $('#btnAdd').click(function () {
                var name = $('#addName').val();
                var class_id_list = $('#addClassIds').val();
                console.log(name, class_id_list);
                $.ajax({
                    'url': '/modal-add-teacher/',
                    type: 'POST',
                    data: {'name': name, 'class_id_list': class_id_list},
                    dataType: 'JSON',
                    traditional: true,  // 提交的数据有列表
                    success: function (arg) {
                        console.log(arg);
                        if(arg.status) {
                            location.reload();
                        } else {
                            $('#addError').text(arg.message);
                        }
                    }
                });
            });
        }

        function bindDelete() {
            $('.btn-delete').click(function () {
                var tds = $(this).parent().prevAll();
                var nid = $(tds[2]).text();
                console.log(nid);
                $.ajax({
                    url: '/modal-delete-teacher/',
                    type: 'POST',
                    data: {'nid': nid},
                    dataType: 'JSON',
                    success: function (arg) {
                        if(arg.status) {
                            location.reload();
                        } else {
                            alert(arg.message);
                        }
                    }
                })
            });
        }

        function bindEdit() {
            $('.btn-edit').click(function () {
                $('#shadow, #loading').removeClass('hide');
                $('#editClassIds').empty();
                var tds = $(this).parent().prevAll();
                var nid = $(tds[2]).text();
                var name = $(tds[1]).text();
                $.ajax({
                    url: '/get-all-class-and-selected/',
                    type: 'POST',
                    data: {'nid': nid},
                    dataType: 'JSON',
                    success: function (arg) {
                        console.log(arg);
                        var class_list = arg[0];
                        var class_ids = arg[1];
                        $.each(class_list, function (i, row) {
                            var tag = document.createElement('option');
                            tag.innerText = row.title;
                            tag.setAttribute('value', row.id);
                            if(class_ids.indexOf(row.id) >= 0)
                                tag.setAttribute('selected', true);
                            $('#editClassIds').append(tag);
                        });
                        $('#loading').addClass('hide');
                        $('#editModal').removeClass('hide');
                        $('#edit_tid').val(nid);
                        $('#editName').val(name);
                    }
                });
            });
        }

        function bindEditSubmit() {
            $('#btnEdit').click(function () {
                var tid = $('#edit_tid').val();
                var name = $('#editName').val();
                var class_id_list = $('#editClassIds').val();
                console.log(name, class_id_list);
                $.ajax({
                    'url': '/modal-edit-teacher/',
                    type: 'POST',
                    data: {'tid': tid, 'name': name, 'class_id_list': class_id_list},
                    dataType: 'JSON',
                    traditional: true,  // 提交的数据有列表
                    success: function (arg) {
                        console.log(arg);
                        if(arg.status) {
                            location.reload();
                        } else {
                            $('#editError').text(arg.message);
                        }
                    }
                });
            })
        }

        function bindQuit() {
            $('#quitAdd').click(function () {
                $('#shadow, #addModal').addClass('hide');
            });
            $('#quitEdit').click(function () {
                $('#shadow, #editModal').addClass('hide');
            });
        }
    </script>
</body>
</html>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值