1 Ajax发送数据
发送数据有列表时,需要添加traditional:true
$.ajax({
...
data: {'k1':[1,2,3,4]},
traditional:true,
...
})
发送数据有字典时,需JSON序列化成字符串后发送给后端
$.ajax({
...
data: {'k1':JSON.stringify({'k2':'v2','k3':'v3',...})},
...
})
2 Bootstrap
目标:完善学员管理系统
1.Bootstrap
- 定义:一个包含CSS和JS的一个代码库
- 我们需要了解的是:
- 样式
- 支持响应式布局 @media (导航条)
- 栅格 http://v3.bootcss.com/css/#grid
响应式布局:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.pg-header{
background-color: #2aabd2;
height: 48px;
}
@media (max- 900px) {
.pg-header{
background-color: red;
height: 48px;
}
}
@media (max- 700px) {
.pg-header{
background-color: green;
height: 48px;
}
}
</style>
</head>
<body>
<div class="pg-header"></div>
</body>
</html>
bootstrap导航条
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</body>
</html>
3 学员管理后台布局
Django母版
- 母版:存放所有页面公用代码
- 子版:继承母版并填充自定义当前页面的代码
urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^classes/', views.classes),
url(r'^add_class/', views.add_class),
url(r'^del_class/', views.del_class),
url(r'^edit_class/', views.edit_class),
url(r'^students/', views.students),
url(r'^add_student/', views.add_student),
url(r'^del_student/', views.del_student),
url(r'^edit_student/', views.edit_student),
url(r'^modal_add_class/', views.modal_add_class),
url(r'^modal_edit_class/', views.modal_edit_class),
url(r'^modal_add_student/', views.modal_add_student),
url(r'^modal_edit_student/', views.modal_edit_student),
url(r'^teachers/', views.teachers),
url(r'^add_teacher/', views.add_teacher),
url(r'^edit_teacher/', views.edit_teacher),
url(r'^get_all_class/', views.get_all_class),
url(r'^modal_add_teacher/', views.modal_add_teacher),
url(r'^test/', views.test),
url(r'^layout/', views.layout),
url(r'^login/', views.login),
]
templates.layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
<link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.css">
<link rel="stylesheet" href="/static/css/commons.css">
{% block css1 %}
{% endblock %}
<style>
</style>
</head>
<body>
<div class="pg-header">
<div class="logo left">学生后台管理系统</div>
<div class="avatar right" style="position: relative;">
<img style=" 40px;height: 40px" src="/static/images/tx.png" alt="">
<div class="user-info hide1">
<a href="">个人资料</a>
<a href="">注销</a>
</div>
</div>
<div class="rmenus right">
<a href=""><i class="fa fa-commenting-o" aria-hidden="true"></i> 消息</a>
<a href=""><i class="fa fa-envelope-o" aria-hidden="true"></i> 邮件</a>
</div>
</div>
<div class="pg-body">
<div class="menus">
<a href="/classes/">班级管理</a>
<a href="/students/">学生管理</a>
<a href="/teachers/">老师管理</a>
</div>
<div class="content">
{% block body1 %}
{% endblock %}
</div>
</div>
{% block body2 %}
{% endblock %}
{% block script1 %}
{% endblock %}
</body>
</html>
templates.classes.html
{% extends "layout.html" %}
{% block css1 %}
<link rel="stylesheet" href="/static/css/classes.css">
{% endblock %}
{% block body1 %}
<div>
<ol class="breadcrumb">
<li><a href="#">首页</a></li>
{# <li><a href="#">班级管理</a></li>#}
<li class="active">班级管理</li>
</ol>
</div>
<div style=" 1000px;margin: 20px">
<div style="margin: 10px 0;">
<a href="/add_class/" class="btn btn-primary">添加班级</a>
<a href="#" onclick="showModal();" class="btn btn-info">对话框添加</a>
</div>
<div>
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>ID</th>
<th>班级名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for row in class_list %}
<tr>
<td>{{ row.id }}</td>
<td>{{ row.class_name }}</td>
<td>
<a href="/del_class/?id={{ row.id }}" class="glyphicon glyphicon-trash">删除 |</a>
<a href="#" onclick="return modalEdit(this);" class="glyphicon glyphicon-pencil">对话框编辑 |</a>
<a href="/edit_class/?id={{ row.id }}" class="glyphicon glyphicon-pencil">编辑</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
{% endblock %}
{% block body2 %}
<div id="shadow" class="hide"></div>
<div id="modal" class="hide">
<form action="/modal_add_class/" method="post">
<p><input type="text" name="class_name" id="class_name"></p>
<input type="button" value="提交" onclick="AjaxSend();">
<input type="button" value="取消" onclick="cancleModal();">
<span id="errormsg"></span>
</form>
</div>
<div id="editModal" class="hide">
<h3>编辑框</h3>
<form action="/modal_add_class/" method="post">
<p><input type="text" name="class_name" id="edit_class_name"></p>
<p><input type="text" name="class_id" style="display: none" id="edit_class_id"></p>
<input type="button" value="提交" onclick="editAjaxSend();">
<input type="button" value="取消" onclick="cancleModal();">
<span id="errormsg"></span>
</form>
</div>
{% endblock %}
{% block script1 %}
<script src="/static/jquery-3.2.1.min.js"></script>
<script>
function showModal(){
document.getElementById('shadow').classList.remove('hide');
document.getElementById('modal').classList.remove('hide');
}
function cancleModal() {
document.getElementById('shadow').classList.add('hide');
document.getElementById('modal').classList.add('hide');
document.getElementById('editModal').classList.add('hide');
}
function AjaxSend() {
$.ajax({
url: '/modal_add_class/', // 提交地址
type: 'POST', // 提交方式
data: {'class_name': $('#class_name').val()}, // 提交数据
success: function (data) { // 当服务端处理完成后,返回数据时,该函数自动调用
// data 为返回的数据
if(data == 'ok'){
{# location.href='/classes/';#}
location.reload();
}else{
$('#errormsg').text(data);
}
}
})
}
function modalEdit(self) {
document.getElementById('shadow').classList.remove('hide');
document.getElementById('editModal').classList.remove('hide');
/*
1.获取当前标签
2.当前标签父标签的上方的标签
3.获取当前行班级名,放入编辑框
*/
var row = $(self).parent().prevAll();
var content = $(row[0]).text();
$('#edit_class_name').val(content);
var class_id=$(row[1]).text();
$('#edit_class_id').val(class_id)
}
function editAjaxSend() {
var class_id = $('#edit_class_id').val();
var class_name = $('#edit_class_name').val();
$.ajax({
url:'/modal_edit_class/',
type:'POST',
data: {'class_id':class_id,'class_name':class_name},
success:function (arg) {
// arg 是字符串类型
// JSON.parse(字符串) => 对象
// JSON.stringify(对象) => 字符串
arg = JSON.parse(arg);
if(arg.status){
location.reload();
}else{
alert(arg.message);
}
}
})
}
</script>
{% endblock %}
templates.teachers.html
{% extends "layout.html" %}
{% block css1 %}
<style>
.shadow{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: black;
opacity: 0.3;
z-index: 999;
}
.add_modal,.edit_modal{
position: fixed;
top: 50%;
left: 50%;
400px;
height: 300px;
margin-top: -150px;
margin-left: -200px;
z-index: 1000;
background-color: white;
}
.hide{
display: none;
}
.loading{
position: fixed;
32px;
height: 32px;
left: 50%;
top:50%;
margin-left: -16px;
margin-top: -16px;
background-image: url("/static/images/loading.gif");
}
</style>
{% endblock %}
{% block body1 %}
<div>
<ol class="breadcrumb">
<li><a href="#">首页</a></li>
{# <li><a href="#">老师管理</a></li>#}
<li class="active">老师管理</li>
</ol>
</div>
<div style=" 1200px;margin: 20px">
<div style="margin-bottom: 20px">
<a href="/add_teacher/" class="btn btn-primary">添加老师</a>
<a href="#" id="btnAdd" class="btn btn-info">对话框添加</a>
</div>
<div>
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>ID</th>
<th>老师姓名</th>
<th>任教班级</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for row in teacher_list %}
<tr>
<td>{{ row.teacher_id }}</td>
<td>{{ row.teacher_name }}</td>
<td>
{% for item in row.class_name %}
<span style="display: inline-block;margin-right: 10px;">{{ item }}</span>
{% endfor %}
</td>
<td>
<a href="/edit_teacher/?teacher_id={{ row.teacher_id }}">编辑</a>
<a>删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
{% endblock %}
{% block body2 %}
<div class="shadow hide"></div>
<div class="add_modal hide">
<p>
<input id="addTeacherName" type="text" name="teacher_name" placeholder="老师姓名">
</p>
<p>任教班级
<select multiple size="10" id="addClassIds" name="class_id">
</select>
</p>
<input id="btnAddTeacher" type="button" value="添加">
<input id="btnCancelModal" type="button" value="取消">
<span id="addErrorMsg"></span>
</div>
<div id="loading" class="loading hide"></div>
{% endblock %}
{% block script1 %}
<script src="/static/jquery-3.2.1.min.js"></script>
<script>
$(function () {
bindAdd();
bindBtnAddTeacher();
});
function bindAdd() {
$('#btnAdd').click(function () {
$('#loading').removeClass('hide');
/*
发送ajax请求,获取所有班级信息
在班级列表下拉框中生成option
*/
$.ajax({
url: '/get_all_class/',
type: 'POST',
dataType: 'JSON',
success:function (arg) {
// 将所有的数据添加到select option框
$.each(arg,function (i,row) {
$('.shadow,.add_modal').removeClass('hide')
var tag = document.createElement('option');
tag.innerHTML = row.class_name;
tag.setAttribute('value',row.class_id);
$('#addClassIds').append(tag);
})
}
})
});
$('#btnCancelModal').click(function () {
$('.shadow,.add_modal').addClass('hide')
})
}
function bindBtnAddTeacher() {
$('#btnAddTeacher').click(function () {
var teacher_name = $('#addTeacherName').val();
var class_id_list = $('#addClassIds').val();
console.log(teacher_name, class_id_list);
$.ajax({
url:'/modal_add_teacher/',
type: 'POST',
data: {'teacher_name': teacher_name,'class_id_list':class_id_list},
traditional:true, // 如果提交的数据的值有列表,则需要添加此属性
dataType: 'JSON',
success:function (arg) {
if(arg.status){
location.reload();
}else{
{# $('#addErrorMsg').innerText = arg.message;#}
alert(arg.message)
}
}
})
})
}
</script>
{% endblock %}
static.css.classes.css
.hide{
display: none;
}
#shadow{
position: fixed;
left:0;
top:0;
right: 0;
bottom: 0;
background-color: black;
opacity: 0.4;
z-index: 999;
}
#modal,#editModal{
z-index: 1000;
position: fixed;
left: 50%;
top: 50%;
height: 300px;
400px;
background-color: white;
margin-left: -200px;
margin-top: -150px;
}
static.css.commons.css
body{
margin: 0;
}
.left{
float: left;
}
.right{
float: right;
}
.pg-header{
height: 48px;
min- 1190px;
line-height: 48px;
background-color: #2aabd2;
}
.menus{
200px;
position: absolute;
left: 0;
bottom: 0;
top: 48px;
border-right: 1px solid #dddddd;
background-color: #dddddd;
}
.content{
position: absolute;
left: 200px;
right: 0;
top: 48px;
bottom: 0;
min- 990px;
overflow: scroll;
z-index: 99;
}
.pg-header .logo{
color: white;
font-size: large;
200px;
text-align: center;
border-right: 1px solid red;
}
.pg-header .rmenus a{
display: inline-block;
padding: 0 15px;
color: white;
}
.pg-header .rmenus a:hover{
background-color: gold;
}
.pg-header .avatar{
padding: 0 20px;
}
.pg-header .avatar img{
border-radius: 50%;
}
.pg-header .avatar .user-info {
120px;
position: absolute;
top: 48px;
right: 2px;
background-color: white;
z-index: 100;
border: 1px solid #dddddd;
}
.pg-header .avatar .user-info a{
display: block;
text-align: center;
}
.hide1{
display: none;
}
.pg-header .avatar:hover .user-info{
display: block;
}
.pg-body .menus a{
display: block;
padding: 10px 5px;
border-bottom: solid 1px white;
text-align: center;
}
4 Cookie
- Cookie是保存在用户浏览器端的键值对
- 服务端可以向用户浏览器端写cookie
- 客户端每次发起请求时,会携带cookie去
cookie用途:
- 用户登录,保持用户登录状态
- 投票系统(cookie禁用可破解)
app01.views.py
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
elif request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'alex' and password == '123':
obj = redirect('/classes/')
# obj.set_cookie('ticket','dhffjalih',max_age=10)
# set_cookie参数:
# 第一个参数 key
# 第二个参数 value
# max_age:超时时间,单位秒
# path:生效的路径 默认为 / 全局生效
# domain:生效的域名 默认为当前域名 做单点登录时会用到
#
# 设置加密cookie
obj.set_signed_cookie('ticket','dhffjalih',salt='abc')
return obj
else:
return render(request, 'login.html')
def classes(request):
# 去请求的cookie中找凭证
# tk = request.COOKIES.get('ticket')
# 获取加密cookie
tk = request.get_signed_cookie('ticket',salt='abc')
if not tk:
return redirect('/login/')
conn = pymysql.connect(
host='localhost',
port=3306,
user='root',
passwd='123456',
db='db03',
charset='utf8'
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute(
'select id,class_name from class order by id;'
)
class_list = cursor.fetchall()
cursor.close()
conn.close()
return render(request, 'classes.html', {'class_list': class_list})
PS:可以用装饰器完成所有函数的认证登录功能