后台管理系统页面母板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} {% endblock %}</title>
<style>
.toparea {
height: 80px;
width: 100%;
background-color: beige;
text-align: center;
vertical-align: center;
}
.toparea .welcom {
position: fixed;
left: 40%;
top: 30px;
font-size: 30px;
font-style: italic;
color: orange;
}
.left_menu {
position: fixed;
width: 200px;
height: 100%;
background-color: cornflowerblue;
}
.content_area {
position: fixed;
left: 200px;
width: 100%;
height: 100%;
background-color: rosybrown;
}
.left_menu .item {
display: block;
padding: 5px 30px;
font-size: 30px;
border-bottom: solid 1px orange;
}
.left_menu .item:hover {
color: orange;
background-color: darkgrey;
}
.left_menu .item.active {
background-color: chocolate;
color: white;
}
</style>
{% block css %} {% endblock %}
</head>
<body>
<div class="toparea">
<div class="welcom">
欢迎使用学校后台管理系统
</div>
<div class="username" style="position: fixed;right:10px;top:40px ;text-align: center;vertical-align: middle " >用户名: {{ username }}
<a href="/classes/logout.html">
注销登陆
</a>
</div>
</div>
<div class="left_menu">
<a id="left_menu_classes" class="item" href="/classes/classes.html">班级管理</a>
<a id="left_menu_teacher" class="item" href="/classes/teacher.html">老师管理</a>
<a id="left_menu_student" class="item" href="/classes/student.html">学生管理</a>
</div>
<div class="content_area">
{% block content %} {% endblock %}
</div>
<script src="/static/jquery-2.1.4.min.js"></script>
<script src="/static/jquery.cookie.js"></script>
{% block js %} {% endblock %}
</body>
</html>
左边跟上边不动,所以做成个木板
下面是scripts
继承
每个子菜单的设置
<div class="left_menu">
<a class="item" href="/classes/manage.html">班级管理</a>
<a class="item" href="/classes/teacher.html">老师管理</a>
<a class="item" href="/classes/student.html">学生管理</a>
</div>
添加一个href 做为链接跳转
学生列表
老师列表
增加一个选中点击的时候变色
<div class="left_menu">
<a id="left_menu_classes" class="item" href="/classes/classes.html">班级管理</a>
<a id="left_menu_teacher" class="item" href="/classes/teacher.html">老师管理</a>
<a id="left_menu_student" class="item" href="/classes/student.html">学生管理</a>
</div>
第一步:base.html中先每一个菜单添加一个ID,用于JS来获取
<style>
.left_menu .item:active {
background-color: chocolate;
color: white;
}
</style>
第二步:base.html中设置如果有class标签的就变成什么颜色
{% block js %}
<script>
$(function (){
$("#left_menu_classes").addClass("active");
})
</script>
{% endblock %}
第三步:在每一个子html文件中,添加如上代码,意思是添加一个class,名字为“active”,techer,student,classes 3个子html文件都要添加
现在在哪个菜单下,哪个菜单就是单独的颜色。
动态的选中现在在用的菜单(现在在哪个菜单上哪个菜单就深色)
模板已经引用jquery所以,这里不用再引入了
如果点了别的页面后,页面自动刷新,所以不用设置移除
设置margin为0
<style>
body {
margin: 0;
}
</style>
内容块
目标是点击班级管理后,先显示出所有数据库里面有的班级,然后班级可以编辑,可以删除,还可以添加
班级列表
先编辑views,让能够从数据库中获取所有的表
def classes(request):
username = request.session.get("username")
class_list = models.Classes.objects.all()
return render(request, "classes.html",{"username": username,"class_list":class_list})
先获取所有的班级列表
再写前端页面,可以展示这所有的班级
前端表格相关标签:
- 表示表格,表格的所有内容需要写在
和
之间。
- 是 table row 的简称,表示表格的行。表格中有多少个 标签就表示有多少行数据。
- 是 table datacell 的简称,表示表格的单元格,这才是真正存放表格数据的标签。单元格的数据可以是文本、图片、列表、段落、表单、水平线、表格等多种形式。
- 是 table heading 的简称,表示表格的表头。 其实是 单元格的一种变体,本质上还是一种单元格。 一般位于第一行,充当每一列的标题。大多数的浏览器会把表头显示为粗体居中的文本。
- 标签用于组合 HTML 表格的表头内容。
- 元素应该与 和 元素结合起来使用,用来规定表格的各个部分(表头、主体、页脚)。通过使用这些元素,使浏览器有能力支持独立于表格表头和表格页脚的表格主体滚动。当包含多个页面的长的表格被打印时,表格的表头和页脚可被打印在包含表格数据的每张页面上。
- 标签必须被用在以下情境中:作为 元素的子元素,出现在 元素之后,、 和 元素之前。
{% extends "base.html" %}
{% block title %}
{% endblock %}
{% block css %}
{% endblock %}
{% block content %}
<div>
<input type="button" value="添加">
</div>
<table border="1" style="border-collapse: collapse;" >
<caption>班级列表</caption>
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for item in class_list %}
<tr>
<td>{{ item.id }}</td>
<td>{{ item.caption }}</td>
<td><a>编辑</a> | <a>删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block js %}
<script>
$(function (){
$("#left_menu_classes").addClass("active");
})
</script>
{% endblock %}
访问测试
head和body都要加上,不然会自动找上一级,这样容易乱
添加按钮绑定事件
为添加添加一个id
<div>
<input id="id_add" type="button" value="添加">
</div>
绑定JS(目标是执行一个模态对话框)
<script>
$(function (){
$("#left_menu_classes").addClass("active");
})
function bindAddEvent(){
$("#id_add").click(function (
))
}
</script>
写在上面是因为页面一打开就可以准备这个事件,然后如果一点击就应该给出一个页面框框。
写模态对话框(很多位置需要用到模态对话框,所以写在母板)
所谓模态对话框就是在其没有被关闭之前,用户不能与同一个应用程序下的其他窗口进行交互,直到该对话框关闭,比如记事本的另存为窗口。对于非模态对话框,当被打开时,用户既可选择和该对话框进行交互,也可以选择同应用程序的其他窗口交互,比如记事本上帮助内的反馈窗口。
好多地方需要使用到这个模态对话框,所以写在公共位置。所以写在母板
母板中添加3个样式
<style>
.hide {
display: none;
}
.modal{
position: fixed;
top:50%;
left: 50%;
width: 500px;
height: 400px;
background-color: white;
margin-top -250px;
margin-left: -250px;
z-index: 100;
}
.shade{
position: fixed;
top:0;
left: 0;
right: 0;
bottom: 0;
background-color: black;
opacity: 0.5;
z-index: 99;
}
</style>
z-index 属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。 注释:元素可拥有负的 z-index 属性值。 注释:Z-index 仅能在定位元素上奏效(例如 position:absolute;)!
子html中body中添加两个div框
<div class="modal hide"></div>
<div class="shade hide"></div>
回到script中,添加相关绑定的操作
<script>
$(function (){
$("#left_menu_classes").addClass("active");
bindAddEvent()
})
function bindAddEvent(){
$("#id_add").click(function () {
$(".modal,.shade").removeClass("hide");
})
}
</script>
点击展示
模态框中添加几个输入框
<div class="modal hide">
<input class="classes_input" type="text" placeholder="此处输入班级名称">
<input class="classes_submit" type="button" value="确定">
<input class="classes_cancel" type="button" value="取消">
</div>
placeholder 的功能就是在输入框内输入一段文字
<script>
$(function (){
$("#left_menu_classes").addClass("active");
bindCancelModal()
})
function bindCancelModal(){
$("#id_modal_cancel").click(function (){
$(".modal,.shade").addClass("hide");
})
}
</script>
删除的模态对话框
删除按钮绑定操作
点击删除按钮后,对应的条目应该删掉,而这个操作需要使用模态对话框来提示是否确认删除,如果点击确认的话,则将需要删除的数据的ID,POST到后台进行数据库删除。 所以第一步,先搞定点击删除后弹出一个框来
第一步:点击删除弹框
删除按钮绑定事件
{% for item in class_list %}
<tr>
<td>{{ item.id }}</td>
<td>{{ item.caption }}</td>
<td><a id="button_edit">编辑</a> | <a id="button_delete">删除</a></td>
</tr>
{% endfor %}
添加一个模态对话框
<div class="modal hide">
<input class="classes_input" type="text" placeholder="此处输入班级名称">
<input class="classes_submit" type="button" value="确定">
<td><a class="button_edit">编辑</a> | <a class="button_delete">删除</a></td>
</div>
<div class="shade hide"></div>
<div class="remove hide">
<input class="classes_submit" type="button" value="确定">
<input id="id_remove_cancel" class="classes_cancel" type="button" value="取消">
</div>
如上图,增加了一个class=“remove hide” 的div 标签,里面添加两个按钮,删除的按钮有个ID,ID后面有用
添加remove的style
在base.html中添加
<style>
.remove{
position: fixed;
top:20%;
left: 50%;
width: 500px;
height: 400px;
background-color: coral;
margin-top -250px;
margin-left: -250px;
z-index: 100;
}
</style>
点击之后只需要显示这两个即可。 写remove样式
<script>
$(function (){
$("#left_menu_classes").addClass("active");
bindAddEvent()
bindCancelModal()
bindDeleteEvent()
})
function bindDeleteEvent(){
$("td .button_delete").click(function () {
$(".remove,.shade").removeClass("hide")
})
}
</script>
查看点击效果
第二步 将取消按钮加上去掉模态对话框
<script>
$(function (){
$("#left_menu_classes").addClass("active");
bindAddEvent()
bindCancelModal()
bindDeleteEvent()
})
function bindAddEvent(){
$("#id_add").click(function () {
$(".modal,.shade").removeClass("hide");
})
}
function bindCancelModal(){
$("#id_modal_cancel,#id_remove_cancel").click(function (){
$(".modal,.shade,.remove").addClass("hide");
})
}
function bindDeleteEvent(){
$("td .button_delete").click(function () {
$(".remove,.shade").removeClass("hide");
})
}
</script>
function bindCancelModal() 中添加了#id_remove_cancel,也添加了function bindDeleteEvent() 的函数
添加按钮,使用Form 添加数据
<div class="modal hide">
<form action="/classes/classes.html/" method="post">
{% csrf_token %}
<input class="classes_input" type="text" placeholder="此处输入班级名称" name="caption">
<input class="classes_submit" type="submit" value="确定">
<input id="id_modal_cancel" class="classes_cancel" type="button" value="取消">
</form>
</div>
第一种方式,直接提交的数据写库,然后重定向刷新页面
@auth
def classes(request):
if request.method == "GET":
username = request.session.get("username")
class_list = models.Classes.objects.all()
return render(request, "classes.html",{"username": username,"class_list":class_list})
elif request.method == "POST":
caption = request.POST.get("caption")
models.Classes.objects.create(caption=caption)
return redirect("/classes/classes.html")
操作测试
操作完了后,刷新新的页面,要么get一遍,要么redirect
第二种方式 模态对话框的时候建议使用AJAX的方式提交,不使用FORM
绑定事件 接下来要发ajax数据了,但是在发送之差需要先获取ajax的数据。
第一步,修改html中,添加一个ajax的按钮
<div class="modal hide">
<form action="/classes/classes.html/" method="post">
{% csrf_token %}
<input class="classes_input" type="text" placeholder="此处输入班级名称" name="caption">
<input id="id_modal_cancel" class="classes_cancel" type="button" value="取消">
<input class="classes_submit" id="modal_ajax_submit" type="button" value="确定">
</form>
</div>
注意,使用ajax提交,form中就不是submit了,普通的button,动作在ajax中进行定义
success就是用户返回的数据了 ajax与form有不同,form有跳转
第二步:修改views方法,处理ajax的数据
@auth
def classes(request):
if request.method == "GET":
username = request.session.get("username")
class_list = models.Classes.objects.all()
return render(request, "classes.html",{"username": username,"class_list":class_list})
elif request.method == "POST":
import json
response_data = {"status": True, "error": None,"data": None}
caption = request.POST.get("caption",None)
if caption:
models.Classes.objects.create(caption=caption)
else:
response_data["status"] = False
response_data["error"] = "课程名称不能为空"
return HttpResponse(json.dumps(response_data))
第三步 添加JS绑定动作,使用AJAX进行提交
function bindSubmitModal(){
$("#modal_ajax_submit").click(function (){
var value = $('.modal input[name="caption"]').val()
$.ajax({
url: "/classes/classes.html/",
type: "POST",
headers: {"X-CSRFToken": $.cookie("csrftoken")},
dataType:"JSON",
data: {caption: value},
success: function (data){
if (!data.status){
alert(data.error);
}else {
location.reload()
}
},
})
})
}
注意csrf_token的添加方法
第四步 添加成功测试
第五步 添加失败的测试(填入数据为空的时候)
两种方式,一种是type直接定义返回为jason,那就不用json.parse了
添加成功(AJAX提交成功)后的处理方式
第一种方式,直接局部刷新,这样就相当于重新从数据库拉取了一次数据。
成功后直接关闭—两种处理方式,第一种是location.reload() 直接将这个位置刷新一下,不需要整个页面刷新。
第二种方式,将添加的值直接显示在前端两面的最后
这句代码表示“当前页面刷新一下。”这是一种解决方式,还有一种方式,不刷新,将数据放到表后面。
第一步 修改html,将
<script>
$(function (){
$("#left_menu_classes").addClass("active");
bindAddEvent()
bindCancelModal()
bindDeleteEvent()
bindSubmitModal()
})
function bindSubmitModal(){
$("#modal_ajax_submit").click(function (){
var value = $('.modal input[name="caption"]').val()
$.ajax({
url: "/classes/classes.html/",
type: "POST",
headers: {"X-CSRFToken": $.cookie("csrftoken")},
dataType:"JSON",
data: {caption: value},
success: function (rep){
if (!rep.status){
alert(rep.error);
}else {
var tr = document.createElement("tr");
var td1 = document.createElement("td");
var td2 = document.createElement("td");
var td3 = document.createElement("td");
var input1 = document.createElement("input");
var input2 = document.createElement("input");
td1.innerHTML= rep.data.id;
td2.innerHTML= rep.data.caption;
input1.value = "编辑";
input1.className = "button_edit";
input1.type = "button";
input2.value = "删除";
input2.className = "button_delete";
input2.type = "button";
td3.innerText = " | ";
$(td3).prepend(input1);
$(td3).append(input2);
$(tr).append(td1);
$(tr).append(td2);
$(tr).append(td3);
$("table tbody").append(tr);
$(".modal,.shade").addClass("hide");
}
},
})
})
}
</script>
第二步 修改views函数
def classes(request):
if request.method == "GET":
username = request.session.get("username")
class_list = models.Classes.objects.all()
return render(request, "classes.html",{"username": username,"class_list":class_list})
elif request.method == "POST":
import json
response_data = {"status": True, "error": None,"data": None}
caption = request.POST.get("caption",None)
if caption:
obj = models.Classes.objects.create(caption=caption)
response_data["data"] = {"id":obj.id,"caption":obj.caption}
else:
response_data["status"] = False
response_data["error"] = "课程名称不能为空"
return HttpResponse(json.dumps(response_data))
> obj = models.Classes.objects.create(caption=caption)
> response_data["data"] = {"id":obj.id,"caption":obj.caption}
注意这两句, 写完之后将数据追加至最后。ID和数据来自哪儿呢? AJAX提交数据后,会写库,但是写库也是一个对象,所以会有id与caption,将这两个值返回给前端即可,这样只需要返回一个字典给前端,不需要返回整个页面,节省了网络带宽
绑定委托
因为新加入的一行数据是通过ajax的函数方法在表格后面追加的标签,数据来源于后台提供的字典数据,这个时候虽然有数据,有标签,有class等属性,但是并不是绑定动作,动作都是在页面渲染的时候绑定的,所以这个时候需要进行委托,需要将比如编辑和删除的动作委托到上层标签上,这样即使添加的数据也可以进行点击操作。
修改删除js
function bindDeleteEvent(){
$("tbody").on("click",".button_delete",function () {
$(".remove,.shade").removeClass("hide");
})
}
访问测试
添加数据之跳转URL方式提交
第一步:classes.html中添加一个按钮用于点击后跳转
<div>
<input id="id_add" type="button" value="添加">
<a href="/classes/add_classes.html">
<input type="button" value="跳转添加">
</a>
</div>
第二步:新建一个add_classes.html
{% extends "base.html" %}
{% block title %}
{% endblock %}
{% block css %}
{% endblock %}
{% block content %}
<h1>添加班级</h1>
<form method="post" action="/classes/add_classes.html/">
<input name="caption" placeholder="请输入你要添加的班级" type="text">
<input type="submit" value="提交">
<input type="button" value="取消">
{% csrf_token %}
<a>{{ message }}</a>
</form>
{% endblock %}
{% block js %}
<script>
$(function (){
$("#left_menu_classes").addClass("active");
})
</script>
{% endblock %}
第三步:urls
urlpatterns = [
path(r"add_classes.html/",views.add_classes),
]
第四步 views
def add_classes(request):
message = ""
if request.method == "GET":
return render(request,"add_classes.html",{"message":message})
elif request.method == "POST":
caption = request.POST.get("caption",None)
if caption:
obj = models.Classes.objects.create(caption=caption)
return redirect("/classes/classes.html")
else:
message = "班级不允许为空,请重新输入"
return render(request, "add_classes.html",{"message":message})
else:
return redirect("/classes/classes.html")
输入值测试
空值测试
两种方式对比
模态对话框使用JS较多,且包含的内容较少,如果填值较多,建议使用跳转网页的方式
|