学神python全栈学习笔记CMDB系统---第二章 python_cmdb_前端样式
第二章 python_cmdb_前端样式
本节所讲内容:
2.1 基于bootstrip的模态框绘制
2.2 基于 forms的表单定义
2.3 基于JQ的前端校验
2.4 表单提交完成注册
2.5 基于cmdb的ajax表单提交
2.6 基于SB-Admin的图表绘制
我们以用户注册表单为例,用bootstrap+jq实现前端样式
2.1 基于bootstrap的模态框绘制
我们把用户注册做到一个模态框里面,模态框看着很复杂,实际上很有规律。
模态框分为两部分:
- 模态框触发按钮
前端界面
\XueGodCMDB36\templates\user_index.html:
通过用户注册触发模态框
{% block page-header %}
<!--模态框触发部分-->
<!--
data-toggle 以何种形式展示模态框 modal、popover
data-target 模态框id
-->
<div class="container-fluid">
<div class="col-md-8">
用户管理
</div>
<div class="col-md-4" style="text-align:right">
<button class="btn btn-default" data-toggle="modal" data-target="#register_user_modal">用户注册</button>
<button class="btn btn-default" data-toggle="modal" data-target="#logout_user_modal">用户退出</button>
</div>
</div>
<!--模态框触发部分结束-->
{% endblock %}
被触发的模态框:
{% block content %}
<!--模态框展示部分-->
<!--
tabindex table 导航的顺序
role = dialog 指定展示的样式(角色)为模态框
aria-labelledby = "MyLabel" 获取值
footer 页脚
-->
<div class="modal fade" data-toggle="modal" id="register_user_modal" tabindex="-1" role="dialog"
aria-labelledby="Mylabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="MyLabel">用户注册</h4>
</div>
<form method="post" id="register_form" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-body">
{% for formitem in user_from %}
<div class="form-group input-group">
<span class="input-group-addon">{{ formitem.label }}</span>
{{ formitem }}
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="submit" class="btn btn-primary" id="add_user_submit">提交</button>
</div>
</form>
</div>
</div>
</div>
<!--模态框展示部分结束-->
模态框效果:
基于 forms的表单定义
Django给我们提供了一个很棒的类叫做forms
定义forms文件
代码如下:
\XueGodCMDB36\User\forms.py:
# !/usr/bin/env python # -*- coding: utf-8 -*- from django import forms from django.forms import widgets class CMDBUserForm(forms.Form): name = forms.CharField( max_length=6, # 长度限制的验证优先级高于前端验证,前后端都要验证,且限制规则相同 min_length=2, label='用户账号', widget=widgets.TextInput( attrs={ 'class': 'form-control', 'required': '', 'minlength': 2, 'maxlength': 6, } ), error_messages={ 'max_length':'用户名最大6位', 'min_length':'用户名最小2位', 'required':'用户名不能为空' } ) password = forms.CharField( max_length=6, min_length=2, label='用户密码', widget=widgets.PasswordInput( attrs={ 'class': 'form-control', 'required': '', 'minlength': 2, 'maxlength': 6, } ) ) nickname = forms.CharField( max_length=6, min_length=2, label='用户姓名', widget=widgets.TextInput( attrs={ 'class': 'form-control', 'required': '', 'minlength': 2, 'maxlength': 6, } ) ) phone = forms.CharField( max_length=11, min_length=11, label='用户电话', widget=widgets.TextInput( attrs={ 'class': 'form-control', 'required': '', 'minlength': 11, 'maxlength': 11, } ) ) email = forms.EmailField( label='用户邮箱', widget=widgets.EmailInput( attrs={ 'class': 'form-control', 'required': '', } ) ) photo = forms.ImageField( label='用户照片', allow_empty_file=True, widget=widgets.FileInput( attrs={ 'id': 'logo_file', 'class': 'file-input-new btn btn-primary btn-file', 'style': " margin: auto;", 'required': '', } ) )
视图加载,前端渲染
修改forms的样式
我们修改forms的样式,不能随着自己的想法,要安装模板的格式
给forms添加bootstrap样式
循环生成表单
代码如下:
{% block content %} <!--模态框展示部分--> <!-- tabindex table 导航的顺序 role = dialog 指定展示的样式(角色)为模态框 aria-labelledby = "MyLabel" 获取值 footer 页脚 --> <div class="modal fade" data-toggle="modal" id="register_user_modal" tabindex="-1" role="dialog" aria-labelledby="Mylabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title" id="MyLabel">用户注册</h4> </div> <form method="post" id="register_form" enctype="multipart/form-data"> {% csrf_token %} <div class="modal-body"> {% for formitem in user_from %} <div class="form-group input-group"> <span class="input-group-addon">{{ formitem.label }}</span> {{ formitem }} </div> {% endfor %} </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="submit" class="btn btn-primary" id="add_user_submit">提交</button> </div> </form> </div> </div> </div> <!--模态框展示部分结束--> <div class="modal fade" data-toggle="modal" id="logout_user_modal" tabindex="-1" role="dialog" aria-labelledby="Mylabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title" id="MyLabel">用户注销</h4> </div> <form action="{% url 'logout' %}" method="get" id="logout_dialog" > {% csrf_token %} <div class="modal-body"> <div class="form-group input-group"> 退出当前用户? {# <span class="input-group-addon">{{ formitem.label }}</span>#} {# {{ formitem }}#} </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="submit" class="btn btn-primary" id="logout_user_submit">提交</button> </div> </form> </div> </div> </div> <!--模态框展示部分结束--> <div class="container-fluid"> <div class="col-md-6"> </div> </div> {% endblock %}
基于JQ的前端校验
From前端校验对于所有同学来说,都是一个难点,今天推荐jq扩展框架jq_validate是jq扩展的校验库,拥有丰富的校验功能,有jq开发小组成员开发。
- 导入框架
下载jq-validation包
取出自己需要的jq脚本
Jquery.validate.min.js 校验功能的压缩包
Jquery.validate支持40多种语言,我们还需要下载汉化包
我们将两个js脚本复制到我们的目录下
然后执行导入
form上添加校验属性:
代码:
# !/usr/bin/env python # -*- coding: utf-8 -*- from django import forms from django.forms import widgets class CMDBUserForm(forms.Form): name = forms.CharField( max_length=6, # 长度限制的验证优先级高于前端验证,前后端都要验证,且限制规则相同 min_length=2, label='用户账号', widget=widgets.TextInput( attrs={ 'class': 'form-control', 'required': '', 'minlength': 2, 'maxlength': 6, } ), error_messages={ 'max_length':'用户名最大6位', 'min_length':'用户名最小2位', 'required':'用户名不能为空' } ) password = forms.CharField( max_length=6, min_length=2, label='用户密码', widget=widgets.PasswordInput( attrs={ 'class': 'form-control', 'required': '', 'minlength': 2, 'maxlength': 6, } ) ) nickname = forms.CharField( max_length=6, min_length=2, label='用户姓名', widget=widgets.TextInput( attrs={ 'class': 'form-control', 'required': '', 'minlength': 2, 'maxlength': 6, } ) ) phone = forms.CharField( max_length=11, min_length=11, label='用户电话', widget=widgets.TextInput( attrs={ 'class': 'form-control', 'required': '', 'minlength': 11, 'maxlength': 11, } ) ) email = forms.EmailField( label='用户邮箱', widget=widgets.EmailInput( attrs={ 'class': 'form-control', 'required': '', } ) ) photo = forms.ImageField( label='用户照片', allow_empty_file=True, widget=widgets.FileInput( attrs={ 'id': 'logo_file', 'class': 'file-input-new btn btn-primary btn-file', 'style': " margin: auto;", 'required': '', } ) ) 前端js定义校验规则和提示
代码:
{% block script %} <!-- jQuery --> <script src="/static/vendor/jquery/jquery.min.js"></script> <!-- Bootstrap Core JavaScript --> <script src="/static/vendor/bootstrap/js/bootstrap.min.js"></script> <!-- Metis Menu Plugin JavaScript --> <script src="/static/vendor/metisMenu/metisMenu.min.js"></script> <!-- DataTables JavaScript --> <script src="/static/vendor/datatables/js/jquery.dataTables.min.js"></script> <script src="/static/vendor/datatables-plugins/dataTables.bootstrap.min.js"></script> <script src="/static/vendor/datatables-responsive/dataTables.responsive.js"></script> <!-- Custom Theme JavaScript --> <script src="/static/dist/js/sb-admin-2.js"></script> <!-- 前端表单验证js,注意2个库的顺序 --> <script src="/static/vendor/jquery/jquery.validate.min.js"></script> <script src="/static/vendor/jquery/messages_zh.min.js"></script> <!-- Page-Level Demo Scripts - Tables - Use for reference --> <script> $().ready( function () { $('#register_form').validate( { <!-- 前端表单验证规则 --> rules: { id_name: { required: true, minlength: 2, maxlength: 6, }, id_password: { required: true, minlength: 2, maxlength: 6, }, id_nickname: { required: true, minlength: 2, maxlength: 6, }, id_phone: { required: true, }, id_email: { required: true, } }, <!-- 前端表单验证失败提示消息 --> messages: { id_name: { required: '用户名不能为空', minlength: '用户名长度必须大于2', maxlength: '用户名长度必须小于6', }, id_password: { required: '密码不能为空', minlength: '密码长度必须大于2', maxlength: '密码长度必须小于6', }, id_nickname: { required: '用户姓名不能为空', minlength: '用户姓名长度必须大于2', maxlength: '用户姓名长度必须小于6', }, id_phone: { required: '', minlength: '请输入正确长度(不少于11位)的用户电话', maxlength: '请输入正确长度(不大于11位)的用户电话', }, id_email: { required: '用户邮箱不能为空', }, }, submitHandler: function (form) { data = $('#register_form').serializeArray()//没有文件,可以用这个方式获取form数据 var formdata = new FormData();//获取含有文件的form数据 for (var k in data){ console.log(data[k]) formdata.append(data[k]['name'],data[k]['value']) } //添加文件到formdata file = $('#logo_file')[0].files[0] console.log(file) formdata.append('photo',file) //获取csrftoken,提交给到后端验证 var csrftoken = data[0]['value'] $.post({ url:'/index/', data:formdata, async:false, traditional:true,//是否深度序列化数据,true为不深度 processData:false,//是否序列化 contentType:false,//信息的类型 beforeSend:function (xhr,settings) { xhr.setRequestHeader('X-CSRFToken',csrftoken) }, <!--=========后台验证结果在此返回,前台判断显示==========--> success:function (data) { console.log(data['data']) if (data['status'] == 'success'){ toastr.success(data['data']) //等待弹出toastr后再刷新页面 setTimeout(function(){ window.location.reload() }, 2000); }//保存失败,文件大小太大 if (data['status'] == 'save fail'){ toastr.error(data['data']) } if (data['status'] == 'is_valid error'){ toastr.error(data['data']) } }, error:function (error) { console.log(error['data']) toastr.error(error['data']) }, }) }, } ) } ) </script> {% endblock %}
注意:最长限制不会显示,只会超过最长长度后无法输入
完整代码如下:
前端:
{% extends 'base.html' %} {% block title %} <title>S-CMDB管理系统 首页</title> {% endblock %} {% block style %} <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <!-- Bootstrap Core CSS --> <link href="/static/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <!-- MetisMenu CSS --> <link href="/static/vendor/metisMenu/metisMenu.min.css" rel="stylesheet"> <!-- DataTables CSS --> <link href="/static/vendor/datatables-plugins/dataTables.bootstrap.css" rel="stylesheet"> <!-- DataTables Responsive CSS --> <link href="/static/vendor/datatables-responsive/dataTables.responsive.css" rel="stylesheet"> <!-- Custom CSS --> <link href="/static/dist/css/sb-admin-2.css" rel="stylesheet"> <!-- Custom Fonts --> <link href="/static/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css"> {% endblock %} {% block navbar-brand %} <a class="navbar-brand" href="yl/index.html">S-CMDB管理系统</a> {% endblock %} {% block page-header %} <!--模态框触发部分--> <!-- data-toggle 以何种形式展示模态框 modal、popover data-target 模态框id --> <div class="container-fluid"> <div class="col-md-8"> 用户管理 </div> <div class="col-md-4" style="text-align:right"> <button class="btn btn-default" data-toggle="modal" data-target="#register_user_modal">用户注册</button> <button class="btn btn-default" data-toggle="modal" data-target="#logout_user_modal">用户退出</button> </div> </div> <!--模态框触发部分结束--> {% endblock %} {% block content %} <!--模态框展示部分--> <!-- tabindex table 导航的顺序 role = dialog 指定展示的样式(角色)为模态框 aria-labelledby = "MyLabel" 获取值 footer 页脚 --> <div class="modal fade" data-toggle="modal" id="register_user_modal" tabindex="-1" role="dialog" aria-labelledby="Mylabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title" id="MyLabel">用户注册</h4> </div> <form method="post" id="register_form" enctype="multipart/form-data"> {% csrf_token %} <div class="modal-body"> {% for formitem in user_from %} <div class="form-group input-group"> <span class="input-group-addon">{{ formitem.label }}</span> {{ formitem }} </div> {% endfor %} </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="submit" class="btn btn-primary" id="add_user_submit">提交</button> </div> </form> </div> </div> </div> <!--模态框展示部分结束--> <div class="modal fade" data-toggle="modal" id="logout_user_modal" tabindex="-1" role="dialog" aria-labelledby="Mylabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title" id="MyLabel">用户注销</h4> </div> <form action="{% url 'logout' %}" method="get" id="logout_dialog" > {% csrf_token %} <div class="modal-body"> <div class="form-group input-group"> 退出当前用户? {# <span class="input-group-addon">{{ formitem.label }}</span>#} {# {{ formitem }}#} </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="submit" class="btn btn-primary" id="logout_user_submit">提交</button> </div> </form> </div> </div> </div> <!--模态框展示部分结束--> <div class="container-fluid"> <div class="col-md-6"> </div> </div> {% endblock %} {#{% block content %}#} {# <h1>设备管理首页</h1>#} {#{% endblock %}#} {% block script %} <!-- jQuery --> <script src="/static/vendor/jquery/jquery.min.js"></script> <!-- Bootstrap Core JavaScript --> <script src="/static/vendor/bootstrap/js/bootstrap.min.js"></script> <!-- Metis Menu Plugin JavaScript --> <script src="/static/vendor/metisMenu/metisMenu.min.js"></script> <!-- DataTables JavaScript --> <script src="/static/vendor/datatables/js/jquery.dataTables.min.js"></script> <script src="/static/vendor/datatables-plugins/dataTables.bootstrap.min.js"></script> <script src="/static/vendor/datatables-responsive/dataTables.responsive.js"></script> <!-- Custom Theme JavaScript --> <script src="/static/dist/js/sb-admin-2.js"></script> <!-- 前端表单验证js,注意2个库的顺序 --> <script src="/static/vendor/jquery/jquery.validate.min.js"></script> <script src="/static/vendor/jquery/messages_zh.min.js"></script> <!-- Page-Level Demo Scripts - Tables - Use for reference --> <script> $().ready( function () { $('#register_form').validate( { <!-- 前端表单验证规则 --> rules: { id_name: { required: true, minlength: 2, maxlength: 6, }, id_password: { required: true, minlength: 2, maxlength: 6, }, id_nickname: { required: true, minlength: 2, maxlength: 4, }, id_phone: { required: true, }, id_email: { required: true, } }, <!-- 前端表单验证失败提示消息 --> messages: { id_name: { required: '用户名不能为空', minlength: '用户名长度必须大于2', maxlength: '用户名长度必须小于6', }, id_password: { required: '密码不能为空', minlength: '密码长度必须大于2', maxlength: '密码长度必须小于6', }, id_nickname: { required: '用户姓名不能为空', minlength: '用户姓名长度必须大于2', maxlength: '用户姓名长度必须小于6', }, id_phone: { required: '', minlength: '请输入正确长度(不少于11位)的用户电话', maxlength: '请输入正确长度(不大于11位)的用户电话', }, id_email: { required: '用户邮箱不能为空', }, }, submitHandler: function (form) { data = $('#register_form').serializeArray()//没有文件,可以用这个方式获取form数据 var formdata = new FormData();//获取含有文件的form数据 for (var k in data){ console.log(data[k]) formdata.append(data[k]['name'],data[k]['value']) } //添加文件到formdata file = $('#logo_file')[0].files[0] console.log(file) formdata.append('photo',file) //获取csrftoken,提交给到后端验证 var csrftoken = data[0]['value'] $.post({ url:'/index/', data:formdata, async:false, traditional:true,//是否深度序列化数据,true为不深度 processData:false,//是否序列化 contentType:false,//信息的类型 beforeSend:function (xhr,settings) { xhr.setRequestHeader('X-CSRFToken',csrftoken) }, <!--=========后台验证结果在此返回,前台判断显示==========--> success:function (data) { console.log(data['data']) if (data['status'] == 'success'){ toastr.success(data['data']) //等待弹出toastr后再刷新页面 setTimeout(function(){ window.location.reload() }, 2000); }//保存失败,文件大小太大 if (data['status'] == 'save fail'){ toastr.error(data['data']) } if (data['status'] == 'is_valid error'){ toastr.error(data['data']) } }, error:function (error) { console.log(error['data']) toastr.error(error['data']) }, }) }, } ) } ) </script> {% endblock %}
后端view.py:
import os from django.conf import settings from django.http import JsonResponse from django.shortcuts import render, render_to_response, HttpResponseRedirect # Create your views here. from django.views.generic import View from Service.models import CMDBUser from Users.forms import CMDBUserForm def login_validate(func): def is_validate(instance, request, *args, **kwargs): if request.method == 'GET': print(request.path) if request.path == '/user/login': pass elif request.path == '/user/logout': # 退出登陆 instance.logout(request) print(request.GET) print(request.COOKIES) return HttpResponseRedirect('/login/') # 用户已经登入,进行注册操作 elif request.method == 'POST' and request.POST and request.FILES: print('无需验证,返回给index') return func(instance, request) elif request.method == 'POST' and request.POST: print('is_validate') print(request.POST) print(request.COOKIES) if request.POST.get('username'): try: # 判断数据库是否存在该用户 user = CMDBUser.objects.get(username=request.POST.get('username')) # 该用已成功登陆,并有对应数据库里的用户名生成的cookies就可以不用再查询了,直接返回 # if request.COOKIES['login_ok_cookies'] == user.username: # return func(instance, request) print(request.POST.get('username')) # 密码判断 print(user.password) if request.POST.get('password') == user.password: return func(instance, request) else: print('用户%s 密码错误' % (user.username)) return HttpResponseRedirect('/login/') except: print('%s 这个用户不存在' % (request.POST.get('username'))) return HttpResponseRedirect('/login/') else: print('test') return is_validate def logout(request): print(request.COOKIES) # response = render_to_response('login.html') response = render(request, 'login.html') response.delete_cookie('login_ok_cookies') # response.delete_cookie('login_ok_cookie') response.delete_cookie('login_cookie') print(request.COOKIES) print(response.cookies) # return response return HttpResponseRedirect('/login/') class index(View): ''' 用户管理 ''' @login_validate def get(self, request): print(request.method) print(request.GET) print(request) if request.path == '/user/echart': print(request.path) return render(request, 'echart_example.html', locals()) elif request.path == '/user/login': return render_to_response('login.html') elif request.path == '/user/index' or request.path == '/index/': pass user_from = CMDBUserForm() print(locals()) # if request.GET.get() return render(request, 'user_index.html', locals()) @login_validate def post(self, request): # 用户注册提交 if request.POST and request.FILES: ret = {'status': '', 'data': ''} print(request.POST) print(request.FILES) user_form = CMDBUserForm(data=request.POST, files=request.FILES) if user_form.is_valid(): user = CMDBUser() user.username = user_form.cleaned_data['name'] # key值为form里的字段name user.password = user_form.cleaned_data['password'] user.nickname = user_form.cleaned_data['nickname'] user.phone = user_form.cleaned_data['phone'] user.email = user_form.cleaned_data['email'] # 判断上传文件大小,小于某值才能上传 file = request.FILES.get('photo') # 尽量不要使用user_form.cleaned_data['file'] filepath = os.path.join(settings.BASE_DIR, 'static\\images\\%s' % (user_form.cleaned_data['photo'].name)) with open(filepath, 'wb') as f: for chunk in file.chunks(): f.write(chunk) if os.path.getsize(str(filepath)) < 200000: # 上传问文件小于200kB才能保存,并写入数据库 user.photo = filepath user.save() ret['status'] = 'success' ret['data'] = '%s 用户添加成功' % (user.username) print('%s 用户添加成功' % (user.username)) else: ret['status'] = 'save fail' ret['data'] = '保存失败,%s的文件大小不能超过200KB' % (user_form.cleaned_data['photo'].name) os.remove(filepath) print('保存失败,%s的文件大小不能超过200KB' % (user_form.cleaned_data['photo'].name)) else: print(user_form.errors) # ret['status'] = 'is_valid error' ret['data'] = user_form.errors[0] user_from = CMDBUserForm() # 解决第一次注册后,再次点击用户注册无法显示form内容的问题 jr = JsonResponse(ret) # return render(request, 'user_index.html', {'user_from':user_from,'data':jr}) # return render(request, 'user_index.html', locals()) return JsonResponse(ret) # 用户登陆提交 elif request.POST: print(request.POST) print(request.COOKIES) user_from = CMDBUserForm() response = render(request, 'user_index.html', locals()) response.set_cookie('login_ok_cookies', request.POST.get('username'), max_age=3600) print(request.POST) print(request.COOKIES) print(response.cookies) return response def logout(self,request): print(request.COOKIES) # response = render_to_response('login.html') response = render(request, 'login.html') response.delete_cookie('login_ok_cookies') # response.delete_cookie('login_ok_cookie') response.delete_cookie('login_cookie') print(request.COOKIES) print(response.cookies) # return response return HttpResponseRedirect('/login/') # def echart(request): # print(request.path) # return render(request, 'echart_example.html', locals()) Form表单自定义校验 我们的form表单本身提供了好多写好的校验方法,比如: Maxlenth Minlienth Email 但是还是不够我们在工作当中使用,所以forms推出了自定义校验
格式:
- 必须写在forms类里面
- 校验函数名称必须是clean_字段名称
- 所有要校验的数据都可以通过clean_data.get(字段名称)得到
原理如下:
- 如果判断不符合条件,请诱发ValidationError
- 并且如果符合判断,必须将值返回出来
基于cmdb的ajax表单提交
我们上面完成了基本注册了,下面我们来了解一下我们的django+ajax+form+img上传。
Ajax 提交图片
Ajax 提交表单+图片
- 从前端做起
写ajax步骤
- 收集数据
<script> $().ready( function () { $('#register_form').validate( { <!-- 前端表单验证规则 --> rules: { id_name: { required: true, minlength: 2, maxlength: 6, }, id_password: { required: true, minlength: 2, maxlength: 6, }, id_nickname: { required: true, minlength: 2, maxlength: 4, }, id_phone: { required: true, }, id_email: { required: true, } }, <!-- 前端表单验证失败提示消息 --> messages: { id_name: { required: '用户名不能为空', minlength: '用户名长度必须大于2', maxlength: '用户名长度必须小于6', }, id_password: { required: '密码不能为空', minlength: '密码长度必须大于2', maxlength: '密码长度必须小于6', }, id_nickname: { required: '用户姓名不能为空', minlength: '用户姓名长度必须大于2', maxlength: '用户姓名长度必须小于6', }, id_phone: { required: '', minlength: '请输入正确长度(不少于11位)的用户电话', maxlength: '请输入正确长度(不大于11位)的用户电话', }, id_email: { required: '用户邮箱不能为空', }, }, submitHandler: function (form) { data = $('#register_form').serializeArray()//没有文件,可以用这个方式获取form数据 var formdata = new FormData();//获取含有文件的form数据 for (var k in data){ console.log(data[k]) formdata.append(data[k]['name'],data[k]['value']) } //文件的提交方式:添加文件到formdata file = $('#logo_file')[0].files[0] console.log(file) formdata.append('photo',file) //获取csrftoken,提交给到后端验证 var csrftoken = data[0]['value'] $.post({ url:'/index/', data:formdata, async:false, traditional:true,//是否深度序列化数据,true为不深度 processData:false,//是否序列化 contentType:false,//信息的类型 beforeSend:function (xhr,settings) { xhr.setRequestHeader('X-CSRFToken',csrftoken) }, <!--=========后台验证结果在此返回,前台判断显示==========--> success:function (data) { console.log(data['data']) if (data['status'] == 'success'){ toastr.success(data['data']) //等待弹出toastr后再刷新页面 setTimeout(function(){ window.location.reload() }, 2000); }//保存失败,文件大小太大 if (data['status'] == 'save fail'){ toastr.error(data['data']) } if (data['status'] == 'is_valid error'){ toastr.error(data['data']) } }, error:function (error) { console.log(error['data']) toastr.error(error['data']) }, }) }, } ) } ) </script>
如果你的form数据包含文件,我们提交需要用到js的一个类型,FormData
FormData.append(key,value) #添加数据
FormData.set(key,value) #修改数据
FormData.getAll(key) #获取值
声明FormData需要先
var formData = new FromData
完整的form表单数据
收集接口
首先简单编写一个接口,进行了子urls编程
发起请求
FormData将csrf值出入当中之后要进行类似json的封装,所以会失效,csrf实际上如果交易的话,是在请求头部的
代码如下:
优化ajax接收接口。
Ajax注册完整代码
user_index.html:
<script> $().ready( function () { $('#register_form').validate( { <!-- 前端表单验证规则 --> rules: { id_name: { required: true, minlength: 2, maxlength: 6, }, id_password: { required: true, minlength: 2, maxlength: 6, }, id_nickname: { required: true, minlength: 2, maxlength: 4, }, id_phone: { required: true, }, id_email: { required: true, } }, <!-- 前端表单验证失败提示消息 --> messages: { id_name: { required: '用户名不能为空', minlength: '用户名长度必须大于2', maxlength: '用户名长度必须小于6', }, id_password: { required: '密码不能为空', minlength: '密码长度必须大于2', maxlength: '密码长度必须小于6', }, id_nickname: { required: '用户姓名不能为空', minlength: '用户姓名长度必须大于2', maxlength: '用户姓名长度必须小于6', }, id_phone: { required: '', minlength: '请输入正确长度(不少于11位)的用户电话', maxlength: '请输入正确长度(不大于11位)的用户电话', }, id_email: { required: '用户邮箱不能为空', }, }, submitHandler: function (form) { data = $('#register_form').serializeArray()//没有文件,可以用这个方式获取form数据 var formdata = new FormData();//获取含有文件的form数据 for (var k in data){ console.log(data[k]) formdata.append(data[k]['name'],data[k]['value']) } //文件的提交方式:添加文件到formdata file = $('#logo_file')[0].files[0] console.log(file) formdata.append('photo',file) //获取csrftoken,提交给到后端验证 var csrftoken = data[0]['value'] $.post({ url:'/index/', data:formdata, async:false, traditional:true,//是否深度序列化数据,true为不深度 processData:false,//是否序列化 contentType:false,//信息的类型 beforeSend:function (xhr,settings) { xhr.setRequestHeader('X-CSRFToken',csrftoken) }, <!--=========后台验证结果在此返回,前台判断显示==========--> success:function (data) { console.log(data['data']) if (data['status'] == 'success'){ toastr.success(data['data']) //等待2s后弹出toastr后再刷新页面 setTimeout(function(){ window.location.reload() }, 2000); }//保存失败,文件大小太大 if (data['status'] == 'save fail'){ toastr.error(data['data']) } if (data['status'] == 'is_valid error'){ toastr.error(data['data']) } }, error:function (error) { console.log(error['data']) toastr.error(error['data']) }, }) }, } ) } ) </script>
我们完成了注册的核心功能,但是我们还有很大的扩展空间,比如说
注册成功 提示
注册成功 跳转登录(凡是涉及到CMDB或者BIM系统开发,或者其他的管理平台,我们不设置外部注册 )
人物画像
BIM管理
管理流程
基于SB-Admin的图表绘制
我们在做管理平台的时候,难免会做各式各样的可视化图标,当前市场上已经有很多开发好的js框架,我们今天来学习echart.js绘图。
- 下载echart.js放入目录
- 导入echart.js
{% extends "blank.html" %}
{% block title %}
echartsExample
{% endblock %}
{% block style %}
<script src = "/static/js/echarts.min.js"></script>
{% endblock %}
{% block label %}
echartsExample
{% endblock %}
{% block content %}
{% endblock %}
- 开始绘图
{% extends "blank.html" %}
{% block title %}
EchartsExample
{% endblock %}
{% block style %}
<script src = "/static/js/echarts.min.js"></script>
{% endblock %}
{% block label %}
EchartsExample
{% endblock %}
{% block content %}
<div id = "panel" style = "height: 500px; width: 500px;">
</div>
<script>
//初始化画布
var myChart = echarts.init(document.getElementById("panel"))
//定义选项参数
options = {
title: {
text: "我的柱状图"
},
tooltip:{},
legend:{
data:["学科"]
},
xAxis: {
data:["python","php","jave","linux","c"]
},
yAxis: {},
series: [
{
name: "学科",
type: "bar",
data:[1,4,2,5,3]
}
]
};
myChart.setOption(options)
</script>
{% endblock %}
效果如下
- 总结规律
1、echarts 需要定义画布,而且选择器最好用js
2、echarts主要有以下几种类型
1、bar 柱状图
2、line 折线图
3、gauge 仪表盘
4、pie 饼状图
5、island 孤岛图
6、funnel 漏斗图