Python全栈之路-Django(六)

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的一个代码库
  • 我们需要了解的是:

响应式布局:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .pg-header{
            background-color: #2aabd2;
            height: 48px;
        }
        @media (max-width: 900px) {
            .pg-header{
                background-color: red;
                height: 48px;
            }
        }
        @media (max-width: 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="width: 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="width: 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">&laquo;</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">&raquo;</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%;
            width: 400px;
            height: 300px;
            margin-top: -150px;
            margin-left: -200px;
            z-index: 1000;
            background-color: white;
        }
        .hide{
            display: none;
        }
        .loading{
            position: fixed;
            width: 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="width: 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">&laquo;</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">&raquo;</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;
    width: 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-width: 1190px;
    line-height: 48px;
    background-color: #2aabd2;
}
.menus{
    width: 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-width: 990px;
    overflow: scroll;
    z-index: 99;
}
.pg-header .logo{
    color: white;
    font-size: large;
    width: 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 {
    width: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;
}
  • 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:可以用装饰器完成所有函数的认证登录功能

posted on 2017-07-02 16:10  万越天  阅读(297)  评论(0编辑  收藏  举报