Python入门自学进阶-Web框架——11Django实践小项目
Posted kaoa000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python入门自学进阶-Web框架——11Django实践小项目相关的知识,希望对你有一定的参考价值。
以学生、老师、班级管理实现一个小的管理项目。
基本的界面
前端页面的总的框架,因为页头、左侧菜单栏基本是始终保持一致,只是右边内容随不同的菜单项改变,所以,使用一个lindex_base.html作为框架模板。模板中使用块标记来区分不同菜单对应的内容。如下index_base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body
margin: 0;
.menu .item
display: block;
padding: 5px 10px;
border-bottom: 1px solid #dddddd;
# 菜单项是使用a标签,内联标签,改为块级标签,分行显示,并显示一个下划线,美化界面 #
.menu .item:hover
background-color: black;
color: white;
# 鼠标移动到菜单项上时,改变背景及颜色,作为提醒 #
.menu .item.active
background-color: black;
color: white;
# 这个active样式用于在选择了相应菜单后,使菜单呈现选中的状态,提示当前操作是哪个菜单,动态添加 #
% block css %% endblock %
</style>
</head>
<body>
<div style="height: 48px;background-color: black;color: white">
<div style="float: right">当前用户: username | <a href="logout.html">注销</a></div>
</div>
<div>
<div class="menu" style="position: absolute;top:48px;left: 0;bottom: 0;width: 200px;background-color: #eeeeee">
<a id="menu_class" class="item" href="classes.html">班级管理</a>
<a id="menu_student" class="item" href="student.html">学生管理</a>
<a id="menu_teacher" class="item" href="teacher.html">老师管理</a>
</div>
<div style="position: absolute;top:48px;left: 200px;bottom: 0px;right: 0;overflow: auto">
% block content %% endblock %
</div>
</div>
<script src="/static/jquery-3.6.0.js"></script>
# 上面的src的写法要注意,使用pycharm时,会提示具体的文件夹,但是django下应该使用settings.py中的设置,是static,否则前端找不到 #
% block js % % endblock %
</body>
</html>
其他的具体内容页面继承这个页面并进行具体的块填充
1)index.html,欢迎界面
% extends "index_base.html" %
% block css %
% endblock %
% block content %
<h1>欢迎访问后台管理系统</h1>
% endblock %
% block js %
% endblock %
2)classes.html,班级管理页面
% extends "index_base.html" %
% block css %
% endblock %
% block content %
<h1>班级管理页面</h1>
% endblock %
% block js %
% endblock %
3)student.html学生管理页面
% extends "index_base.html" %
% block css %
% endblock %
% block content %
<h1>学生管理页面</h1>
% endblock %
% block js %
% endblock %
5)teacher.html老师管理页面
% extends "index_base.html" %
% block css %
% endblock %
% block content %
<h1>老师管理页面</h1>
% endblock %
% block js %
% endblock %
通过上面的代码框架,可以看出,班级、学生、老师页面只需要填充相应的块内容就可以了,代码简洁、复用高。
当点击了左侧菜单后,要将点击的菜单样式设为active,这是要动态添加的,需要使用js脚本在点击后动态添加,就是点击了哪一个菜单,就为哪一个菜单添加active样式:如下
% extends "index_base.html" %
% block css %
% endblock %
% block content %
<h1>班级管理页面</h1>
% endblock %
% block js %
<script>
$(function ()
$('#menu_class').addClass('active');
)
</script>
% endblock %
老师和学生的页面,只需将$('#menu_class').addClass('active');中的menu_class改为menu_teacher和menu_student。
以班级管理为例,进行功能开发,页面如下:
增加班级时模拟使用模态对话框:形式如下:
def auth(func):
def inner(req,*args,**kwargs):
is_login = req.session.get('is_login')
print(is_login)
if is_login:
return func(req,*args,**kwargs)
else:
return redirect('login.html')
return inner
@auth
def index(req):
current_user = req.session.get('username')
return render(req, "index.html", 'username':current_user)
@auth
def classes(req):
if req.method == "GET":
current_user = req.session.get('username')
cls_list = models.Classes.objects.all()
ret = render(req, "classes.html", 'username':current_user,'cls_list':cls_list)
return ret
elif req.method == "POST":
# 以下代码是form表单提交时的处理方式
caption = req.POST.get('caption',None)
if caption:
models.Classes.objects.create(caption=caption)
return redirect('classes.html')
% extends "index_base.html" %
% block css %
% endblock %
% block content %
<h1>班级管理页面——班级列表</h1>
<hr>
<div>
<input id="id_add" type="button" value="增加班级">
</div>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>班级名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
% for item in cls_list %
<tr>
<td> item.id </td>
<td> item.caption </td>
<td>
<a>修改</a> | <a>删除</a>
</td>
</tr>
% endfor %
</tbody>
</table>
# 下面是增加班级时的操作页面层,一开始是处于隐藏状态,所以class中有hide样式 #
# 增加操作测试两种提交方式,一是form表单提交,二是Ajax提交 #
<div class="modal hide">
<form method="post" action="classes.html">
% csrf_token %
<input name="caption" type="text" placeholder="标题"><br> capmsg
# placeholder属性在输入框中默认显示一个内容,当焦点进入输入框后自动消失 #
<input id="id_modal_cancel" type="button" value="取消增加">
<input type="submit" value="submit确定">
<input id="modal_ajax_submit" type="button" value="Ajax确定">
</form>
</div>
# 下面定义一个遮罩层,用于模拟模态对话框,位置在上一个div,即增加操作层的下面 #
<div class="shade hide"></div>
# 下面是点击删除时弹出的操作页面,未操作前也是隐藏状态,增加hide样式 #
<div class="remove hide">
<input id="id_remove_cancel" type="button" value="取消">
<input type="button" value="确定">
</div>
% endblock %
% block js %
<script>
# 页面加载完毕后执行 #
$(function ()
$('#menu_class').addClass('active');
bindAddEvent();
)
# 下面的函数给增加班级按钮添加click事件,即点击增加班级按钮时执行此函数 #
# 函数的功能就是将modal和shade这两个标签的hide样式删除,使之显示出来。 #
function bindAddEvent()
$('#id_add').click(function ()
$('.modal,.shade').removeClass('hide');
)
</script>
% endblock %
以上是使用form表单提交的方式。后台的代码很简单,判断是post提交时,判断班级名是否为空,为空则不增加,直接跳转到班级管理页面,不为空,数据库增加班级,然后在跳转班级管理页面。
跳转后页面重新刷新,新增加的记录在最后显示。
上面的代码在功能上有点缺陷,我本来想增加一个提示,在数据增加成功时,前端提示增加成功提示框,如果为班级名为空,也有一个提示,班级名不能为空。但是这个看似简单的功能实现起来却异常困难,一直无法解决。主要是点击“submit确定”按钮,后台使用了redirect进行重定向,这时如何向客户端传递内容?一开始想的是如render一样,加一个键值对传过去,但是redirect不支持,后来想用cookie,结果一直无法设置成功。留待以后解决吧。
使用Ajax提交方式:
% extends "index_base.html" %
% block css %
% endblock %
% block content %
<h1>班级管理页面——班级列表</h1>
<hr>
<div>
<input id="id_add" type="button" value="增加班级">
</div>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>班级名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
% for item in cls_list %
<tr>
<td> item.id </td>
<td> item.caption </td>
<td>
<a>修改</a> | <a class="td-delete">删除</a>
</td>
</tr>
% endfor %
</tbody>
</table>
# 下面是增加班级时的操作页面层,一开始是处于隐藏状态,所以class中有hide样式 #
# 增加操作测试两种提交方式,一是form表单提交,二是Ajax提交 #
<div class="modal hide">
<form method="post" action="classes.html">
% csrf_token %
<input name="caption" type="text" placeholder="标题"><br>
# placeholder属性在输入框中默认显示一个内容,当焦点进入输入框后自动消失 #
<input id="id_modal_cancel" type="button" value="取消增加">
<input type="submit" value="submit确定">
<input id="modal_ajax_submit" type="button" value="Ajax确定">
</form>
</div>
# 下面定义一个遮罩层,用于模拟模态对话框,位置在上一个div,即增加操作层的下面 #
<div class="shade hide"></div>
# 下面是点击删除时弹出的操作页面,未操作前也是隐藏状态,增加hide样式 #
<div class="remove hide">
<input name="caption" type="text" placeholder="标题"><br>
<input id="id_remove_cancel" type="button" value="取消">
<input type="button" value="确定">
</div>
% endblock %
% block js %
<script>
# 页面加载完毕后执行 #
$(function ()
$('#menu_class').addClass('active');
bindAddEvent();
bindAddEventAjax();
bindCancelEvent();
bindTdDeleteEvent();
)
# 下面的函数给增加班级按钮添加click事件,即点击增加班级按钮时执行此函数 #
# 函数的功能就是将modal和shade这两个标签的hide样式删除,使之显示出来。 #
function bindAddEvent()
$('#id_add').click(function ()
$('.modal,.shade').removeClass('hide');
)
# 下面函数是对取消按钮的绑定事件,点击取消时,将modal和shade这个两个div增加hide类,隐藏 #
function bindCancelEvent()
$('#id_modal_cancel,#id_remove_cancel').click(function ()
$('.modal,.shade,.remove').addClass('hide');
)
# 下面函数是删除按钮的对应函数,这里暂时只显示删除的输入界面,没做数据的提交 #
function bindTdDeleteEvent()
$('td .td-delete').click(function ()
$('.remove,.shade').removeClass('hide');
)
# 使用Ajax方式进行数据的添加 #
function bindAddEventAjax()
$('#modal_ajax_submit').click(function ()
var val = $('.modal input[name="caption"]').val();
$.ajax(
url:'classes.html',
type: 'POST',
data:caption:val,csrfmiddlewaretoken: ' csrf_token ',
# 数据这里要增加django的csrf安全验证,即发送时要将cookie中的csrftoken一起发送 #
dataType:"JSON",
success:function (rep_data)
#data_t = JSON.parse(rep_data); 如果上面没有dataType设置,这里需要自己手动转换为json对象#
if(!rep_data.status)
alert(rep_data.error);
else
#location.reload(); # 第一种成功后的方法:当前页面刷新,这是班级增加成功时刷新页面 #
# 第二种方法,不刷新页面,直接创建元素添加到页面 #
var tr = document.createElement('tr');
var td1 = document.createElement('td');
td1.innerHTML = rep_data.data.id;
var td2 = document.createElement('td');
td2.innerHTML = rep_data.data.caption;
var td3 = document.createElement('td');
td3.innerText = "|";
var a1 = document.createElement('a');
a1.innerHTML = "编辑";
var a2 = document.createElement('a');
a2.className = "td-delete";
a2.innerHTML = "删除";
$(td3).prepend(a1);
$(td3).append(a2);
$(tr).append(td1);
$(tr).append(td2);
$(tr).append(td3);
$('table tbody').append(tr);
$('.modal,.shade').addClass('hide');
)
)
</script>
% endblock %
后台处理修改一下:
@auth
def classes(req):
print(';;;;;',req.GET.get('flags',None))
if req.method == "GET":
current_user = req.session.get('username')
cls_list = models.Classes.objects.all()
ret = render(req, "classes.html", 'username':current_user,'cls_list':cls_list)
return ret
elif req.method == "POST":
# 以下代码是form表单提交时的处理方式
caption = req.POST.get('caption',None)
# form表单提交时的后台处理,使用了redirect跳转
# if caption:
# models.Classes.objects.create(caption=caption)
# return redirect('classes.html')
# Ajax提交时的后台处理
response_dict = 'status':True,'error':None,'data':None
if caption:
obj = models.Classes.objects.create(caption=caption)
response_dict['data'] = 'id':obj.id,'caption':obj.caption
print('添加成功')
else:
response_dict['status'] = False
response_dict['error'] = '班名不能为空'
return HttpResponse(json.dumps(response_dict))
以上是Ajax的提交方法,这里有一个问题,就是ajax提交后,局部刷新classes.html页面增加的数据,其编辑 | 删除所对应的事件没有加上,点击时没有反应。主要是元素的.click事件是一个静态的绑定,对之后动态添加的事件无能为力,改为使用具有事件委托功能的on方法进行绑定。
on方法使用:假设:
<ul>
<li>菜单1</li>
<li>菜单2</li>
</ul>
给li元素绑定事件:
1、$('li').click(function());
2、$('li').on('click',function());
3、$('ul').on('click','li',function());
第1、2种等价,属于静态绑定,第3种的写法注意,是父元素使用on,在方法参数2中写被绑定的元素,是事件委托形式,动态添加。注意,第3中方法的ul不能是动态添加的
function bindTdDeleteEvent()
// $('td .td-delete').click(function ()
// $('.remove,.shade').removeClass('hide');
// ) // s上面是静态绑定
//下面的是事件委托,动态绑定,注意,使用tbody进行委托,不能使用tr或td,因为这两个也是动态添加的。
$('tbody').on('click','.td-delete',function ()
$('.remove,.shade').removeClass('hide');
)
前面的添加是使用了模态对话框进行添加,这适合数据量少,逻辑简单的情况,如果数据量很大,最好使用单独的页面:
<!--将下面的语句修改 -->
<div>
<input id="id_add" type="button" value="增加班级">
</div>
<!--改为a标签,单独开一个页面 -->
<div>
<a href="add_class.html">增加班级</a>
</div>
增加一个页面:add_class.html
% block content %
<h1>添加班级页面</h1>
<hr>
<form action="add_class.html" method="post">
% csrf_token %
<input type="text" name="caption" placeholder="班级名称"> msg <br>
<input type="submit" value="submit确定">
</form>
% endblock %
后台视图:
@auth
def add_class(req):
message = ""
if req.method == "GET":
return render(req,'add_class.html','msg':message)
else:
caption = req.POST.get('caption', None)
if caption:
models.Classes.objects.create(caption=caption)
return redirect('classes.html')
else:
message = "名称不能为空"
return render(req,'add_class.html','msg':message)
班级信息的显示,前面是全部列在一个页面,如果数据很多,就不能一下全部显示出来,需要分页显示。自定义分页:
修改classes.html:
<h1>班级管理页面——班级列表</h1>
<hr>
<div>
<input id="id_add" type="button" value="增加班级">
<a href="add_class.html">增加班级-单独页面</a>
</div>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>班级名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
% for item in cls_list %
<tr>
<td> item.id </td>
<td> item.caption </td>
<td>
<a>修改</a> | <a class="td-delete">删除</a>
</td>
</tr>
% endfor %
</tbody>
</table>
<div class="pageinfo">
<!-- 可以将这段代码在后台进行组织,然后直接使用模板语言引用
<a href="classes.html?p=1">1</a>
<a href="classes.html?p=2">2</a>
<a href="classes.html?p=3">3</a>
<a href="classes.html?p=4">4</a>
-->
page_tag | safe
<!-- 加上管道符和safe,是告诉浏览器进行渲染,否则作为字符串显示,是安全机制 -->
<!-- 也可以在后台加上安全机制,引入from django.utils.safestring import mark_safe,使用mark_safe(page_tag),-->
修改后台视图函数:
@auth
def classes(req):
from django.utils.safestring import mark_safe
print(';;;;;',req.GET.get('flags',None))
if req.method == "GET":
current_user = req.session.get('username')
current_page = req.GET.get('p',1)
current_page = int(current_page)
total_count = models.Classes.objects.all().count()
# 计算按每页10条记录计算,共多少页
v,a = divmod(total_count,10)
if a != 0:
v += 1
page_list = []
# 比较简单的实现如下,将所有页码都显示出来,但是如果页比较多,这个实现不好
# for i in range(1,v+1):
# if i == current_page:
# page_list.append('<a class="active" href="classes.html?p=%s">%s</a>' % (i,i))
# else:
# page_list.append('<a href="classes.html?p=%s">%s</a>' % (i,i))
# page_list.append('<a href="classes.html?p=%s">下一页</a>' % (current_page+1,))
# page_tag = "".join(page_list)
# 判断输入的页码是否在合理范围内,因为是get请求,可以在地址栏中随意输入
# 如果请求的页码小于1,就设为1,如果请求的页码大于总页码,就设为最后一个页码
if current_page < 1 :
current_page = 1
print(current_page)
elif current_page > v:
current_page = v
# 页码只显示最多N条,这里假设11条,加上前后的上一页和下一页
# 例如显示第10页,则页码显示10的前后5条,即从5到15页显示在页面上
if v <= 11:
# 页数小于11页,所有页码都显示出来就可以了
page_range_start = 1
page_range_end = v + 1
else:
if current_page < 6:
# 总的页数大于11,并且当前选择的页码小于6,显示的是从1开始的11个页码
page_range_start = 1
page_range_end = 12
else:
# 总的页数大于11,并且当前选择的页码大于等于6,显示的页码是当前页的前后5个加上当前页共11个页码
# 此时,显示的开始页码就是当前页-5,显示的最后页码就是当前页+5,range范围需要在加1.
page_range_start = current_page - 5
page_range_end = current_page +5 +1
if page_range_end > v:
page_range_end = v + 1
page_range_start = v - 10
if current_page == 1:
#当前页码为1时,上一页不能在进行计算
# page_list.append('<a href="#">上一页</a>')
page_list.append('<a href="javascript:void(0)">上一页</a>')
else:
page_list.append('<a href="classes.html?p=%s">上一页</a>' % (current_page - 1,))
for i in range(page_range_start,page_range_end):
if i == current_page:
# 对于当前选择的页码,需要突出显示
page_list.append('<a class="active" href="classes.html?p=%s">%s</a>' % (i,i))
else:
page_list.append('<a href="classes.html?p=%s">%s</a>' % (i,i))
if current_page == v:
# 当前页码为最后一页时,下一页不能在进行计算
page_list.append('<a href="javascript:void(0)">下一页</a>')
else:
page_list.append('<a href="classes.html?p=%s">下一页</a>' % (current_page+1,))
page_tag = "".join(page_list)
# page_tag = '''
# <a href="classes.html?p=1">1</a>
# <a href="classes.html?p=2">2</a>
# <a href="classes.html?p=3">3</a>
# <a href="classes.html?p=4">4</a>
# '''
start = (current_page - 1) * 10
end = current_page * 10
cls_list = models.Classes.objects.all()[start:end]
# 返回的数据,可以使用切片返回部分数据,但是查询数据库是查询了所有的数据
ret = render(req, "classes.html", 'username':current_user,'cls_list':cls_list,'page_tag':mark_safe(page_tag))
# mark_safe(page_tag)使相应的文本在前端被浏览器渲染,否则作为纯文本对待
return ret
elif req.method == "POST":
# 以下代码是form表单提交时的处理方式
caption = req.POST.get('caption',None)
# form表单提交时的后台处理,使用了redirect跳转
# if caption:
# models.Classes.objects.create(caption=caption)
# return redirect('classes.html')
# Ajax提交时的后台处理
response_dict = 'status':True,'error':None,'data':None
if caption:
obj = models.Classes.objects.create(caption=caption)
response_dict['data'] = 'id':obj.id,'caption':obj.caption
print('添加成功')
else:
response_dict['status'] = False
response_dict['error'] = '班名不能为空'
return HttpResponse(json.dumps(response_dict))
对这个分页功能进行分离,抽取成一个独立的模块,做成一个通用的类:PageHelper
# 将分页做成一个通用的工具类
class PageHelper:
# 产生一个分页字符串,形式如下:
# 上一页 1 2 3 4 5 6 7 8 9 10 11 下一页
def __init__(self,total_rec_count,current_page,base_url,page_rec_count=10):
# total_rec_count:查询到的记录的总条数
# current_page:当前页码,即要显示哪一页,点击相应页码时的页码值
# base_url:查询使用的url
# page_rec_count:每页显示的记录条数,默认10条
self.total_rec_count = total_rec_count
self.current_page = current_page
self.page_rec_count = page_rec_count
self.base_url = base_url
@property
def page_rec_start(self):
# 返回当前显示页的记录的开始值
return (self.current_page - 1)*self.page_rec_count
@property
def page_rec_end(self):
# 返回当前显示页的记录的结束值
return self.current_page * self.page_rec_count
def total_page_count(self):
# 计算总共有多少页
v, a = divmod(self.total_rec_count, self.page_rec_count)
if a != 0:
v += 1
return v
def pager_tag_str(self):
# 返回一个页码字符串
v = self.total_page_count()
page_list = []
# 判断输入的页码是否在合理范围内,因为是get请求,可以在地址栏中随意输入
# 如果请求的页码小于1,就设为1,如果请求的页码大于总页码,就设为最后一个页码
if self.current_page < 1:
self.current_page = 1
elif self.current_page > v:
self.current_page = v
# 页码只显示最多N条,这里假设11条,加上前后的上一页和下一页
# 例如显示第10页,则页码显示10的前后5条,即从5到15页显示在页面上
if v <= 11:
# 页数小于11页,所有页码都显示出来就可以了
page_range_start = 1
page_range_end = v + 1
else:
if self.current_page < 6:
# 总的页数大于11,并且当前选择的页码小于6,显示的是从1开始的11个页码
page_range_start = 1
page_range_end = 12
else:
# 总的页数大于11,并且当前选择的页码大于等于6,显示的页码是当前页的前后5个加上当前页共11个页码
# 此时,显示的开始页码就是当前页-5,显示的最后页码就是当前页+5,range范围需要在加1.
page_range_start = self.current_page - 5
page_range_end = self.current_page + 5 + 1
if page_range_end > v:
page_range_end = v + 1
page_range_start = v - 10
if self.current_page == 1:
# 当前页码为1时,上一页不能在进行计算
page_list.append('<a href="javascript:void(0)">上一页</a>')
else:
page_list.append('<a href="%s?p=%s">上一页</a>' % (self.base_url,self.current_page - 1,))
for i in range(page_range_start, page_range_end):
if i == self.current_page:
# 对于当前选择的页码,需要突出显示
page_list.append('<a class="active" href="%s?p=%s">%s</a>' % (self.base_url,i, i))
else:
page_list.append('<a href="%s?p=%s">%s</a>' % (self.base_url,i, i))
if self.current_page == v:
# 当前页码为最后一页时,下一页不能在进行计算
page_list.append('<a href="javascript:void(0)">下一页</a>')
else:
page_list.append('<a href="%s?p=%s">下一页</a>' % (self.base_url,self.current_page + 1,))
page_tag = "".join(page_list)
return page_tag
在项目目录下创建包myutils,将此类放在以page.py保存,然后在使用时引入,然后调用即可:
@auth
def classes(req):
from django.utils.safestring import mark_safe
from myutils.page import PageHelper # 引入分页组件类,调用即可
if req.method == "GET":
current_user = req.session.get('username')
current_page = req.GET.get('p',1)
current_page = int(current_page)
total_count = models.Classes.objects.all().count()
obj = PageHelper(total_count,current_page,'classes.html',20)
page_tag = obj.pager_tag_str()
cls_list = models.Classes.objects.all()[obj.page_rec_start:obj.page_rec_end]
# 返回的数据,可以使用切片返回部分数据,但是查询数据库是查询了所有的数据
ret = render(req, "classes.html", 'username':current_user,'cls_list':cls_list,'page_tag':mark_safe(page_tag))
# mark_safe(page_tag)使相应的文本在前端被浏览器渲染,否则作为纯文本对待
return ret
elif req.method == "POST":
caption = req.POST.get('caption',None)
# Ajax提交时的后台处理
response_dict = 'status':True,'error':None,'data':None
if caption:
obj = models.Classes.objects.create(caption=caption)
response_dict['data'] = 'id':obj.id,'caption':obj.caption
print('添加成功')
else:
response_dict['status'] = False
response_dict['error'] = '班名不能为空'
return HttpResponse(json.dumps(response_dict))
可以看到,经过抽取整理,形成了通用的组件,其他使用的函数中代码更加简洁。
删除班级记录的实现:删除div修改一下:
# 下面是点击删除时弹出的操作页面,未操作前也是隐藏状态,增加hide样式 #
<div class="remove hide">
<input name="id" type="text" class="hide">
<input name="caption" type="text" readonly>
<input id="id_remove_cancel" type="button" value="取消">
<input type="button" value="确定">
</div>
点击删除按钮,对应的id和caption传到删除div中的对应标签中,id是隐藏的,caption只读,显示要删除的班级名称。
对应的删除按钮的绑定事件和删除确定按钮的事件:
function bindTdDeleteEvent()
//下面的是事件委托,动态绑定,注意,使用tbody进行委托,不能使用tr或td,因为这两个也是动态添加的。
$('tbody').on('click','.td-delete',function ()
$('.remove,.shade').removeClass('hide');
var nid = $(this).parent().prevAll()[1].innerText;
var cp = $(this).parent().prevAll()[0].innerText;
$('.remove input[name="caption"]')[0].value = cp;
$('.remove input[name="id"]')[0].value = nid;
)
//下面绑定删除确定按钮的事件
$('.remove #id_remove_del').click(function ()
var nid = $('.remove input[name="id"]')[0].value;
$.ajax(
url: 'del_class.html',
type: 'POST',
data: 'id':nid,csrfmiddlewaretoken: ' csrf_token ',
dataType: 'JSON',
success: function (rep_data)
if(!rep_data.status)
alert(rep_data.error);
$('.remove,.shade').addClass('hide');
else
location.reload();
)
)
后台del_class视图:
@auth
def del_class(req):
response_dict = 'status': True, 'error': None, 'data': None
nid = req.POST.get('id',None)
if not nid:
response_dict['status'] = False
response_dict['error'] = '传递的ID值为空'
else:
res = models.Classes.objects.filter(id=nid).delete()
if not res:
response_dict['status'] = False
response_dict['error'] = '删除失败!'
return HttpResponse(json.dumps(response_dict))
关于修改操作:
借助于增加班级的div,稍微修改一下:
<div class="modal hide">
<form method="post" action="classes.html">
% csrf_token %
<input name="id" type="text" class="hide">
<input name="caption" type="text" placeholder="标题"><br>
# placeholder属性在输入框中默认显示一个内容,当焦点进入输入框后自动消失 #
<input id="id_modal_cancel" type="button" value="取消增加">
<input type="submit" value="submit确定">
<input id="modal_ajax_submit" type="button" value="Ajax确定">
<input id="update_ajax_submit" type="button" value="Ajax修改">
</form>
</div>
增加一个Ajax修改按钮,然后给这个按钮绑定事件:
function bindUpdateEvent()
$('tbody').on('click','.td-edit',function ()
$('.modal,.shade').removeClass('hide');
var tds = $(this).parent().prevAll();
$('.modal input[name="id"]')[0].value = tds[1].innerText;
$('.modal input[name="caption"]')[0].value = tds[0].innerText;
$('#update_ajax_submit').click(function ()
var cp = $('.modal input[name="caption"]').val();
var nid = $('.modal input[name="id"]').val();
$.ajax(
url: 'update_class.html',
type: 'POST',
data: caption: cp,id:nid,csrfmiddlewaretoken:' csrf_token ',
dataType: 'JSON',
success: function (rep_data)
if(!rep_data.status)
alert(rep_data.error);
$('.remove,.shade').addClass('hide');
else
location.reload();
)
)
)
后台视图函数:
@auth
def update_class(req):
if req.method == "POST":
response_dict = 'status': True, 'error': None, 'data': None
nid = req.POST.get('id',None)
cp = req.POST.get('caption',None)
if not nid:
response_dict['status'] = False
response_dict['error'] = "ID为空"
elif ((not cp) or len(cp)==0):
response_dict['status'] = False
response_dict['error'] = "班级名称不能为空"
else:
res = models.Classes.objects.filter(id=nid).update(caption=cp)
print('update:',res)
if not res:
response_dict['status'] = False
response_dict['error'] = "更新失败"
else:
return HttpResponse(json.dumps(response_dict))
程序代码精简:
上面的代码,增加、修改、删除的模态对话框基本相同,考虑将模态对话框统一利用。三个功能使用同一个div层。
<div class="commpage hide">
<form method="post" action="classes.html">
<span class="leixing"></span>
<hr>
% csrf_token %
<input name="id" type="text" class="hide">
<input name="caption" type="text" placeholder="标题"><br>
<input id="id_cancel" type="button" value="取消">
<input id="ajax_submit" type="button" value="确定">
</form>
</div>
关键点是对确定按钮的事件绑定,点击不同的按钮,即点击增加,删除、修改时,对确定按钮绑定不同的事件。
搞了很长时间也没成功,看其中一个删除:
function bindTdDeleteEvent()
//下面的是事件委托,动态绑定,注意,使用tbody进行委托,不能使用tr或td,因为这两个也是动态添加的。
$('tbody').on('click','.td-delete',function ()
$('.commpage,.shade').removeClass('hide');
var nid = $(this).parent().prevAll()[1].innerText;
var cp = $(this).parent().prevAll()[0].innerText;
$('.commpage span')[0].innerText = '删除班级';
$('.commpage input[name="caption"]')[0].value = cp;
// $('.remove input[name="caption"]')[0].readOnly=false/true; //设置输入框是否只读
$('.commpage input[name="id"]')[0].value = nid;
alert('delete1');
)
submit_url = 'del_class.html'
$('.commpage #ajax_submit').off().on('click',function ()
alert('delete2');
var nid = $('.commpage input[name="id"]')[0].value;
$.ajax(
url: submit_url,
type: 'POST',
data: 'id':nid,csrfmiddlewaretoken: ' csrf_token ',
dataType: 'JSON',
success: function (rep_data)
if(!rep_data.status)
alert('删除模块:',rep_data.error);
$('.commpage,.shade').addClass('hide');
$('#ajax_submit').off();
else
location.reload();
$('.commpage,.shade').addClass('hide');
alert("删除模块:chenggong");
$('#ajax_submit').off();
)
)
难搞的地方是如何在绑定事件的时候,删除已经绑定的其他事件,按照在网上查找的方法,主要有unbind()、off()等方法,但是在测试时,前面的事件总是没有删除掉,相当于绑定了一个事件链,会执行多个事件。代码如下:
$('#ajax_submit').off(‘click’).on('click',function ()
按照预想,$('#ajax_submit')这个按钮应该是先删除其上的click事件,然后再绑定新的事件。结果一直出错。先放弃吧。有时间再看看。
以上是关于Python入门自学进阶-Web框架——11Django实践小项目的主要内容,如果未能解决你的问题,请参考以下文章
Python入门自学进阶-Web框架——3Django的URL配置
Python入门自学进阶-Web框架——18FormModelForm
Python入门自学进阶-Web框架——18FormModelForm