在app的admin目录下创建forms.py文件,用来保存admin蓝图中需要使用到的表单
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField, FileField, TextAreaField, SelectField, SelectMultipleField from wtforms.validators import DataRequired, ValidationError, EqualTo from app.models import Admin, Tag, Auth, Role tags = Tag.query.all() # 获取数据库中所有的电影标签 auth_list = Auth.query.all() # 获取数据库中所有的权限列表 role_list = Role.query.all() # 获取数据库中所有的角色列表 # 登录表单 class LoginForm(FlaskForm): """ 管理员登录表单 """ account = StringField( label="账号", validators=[ DataRequired("请输入账号!") ], description='账号', render_kw={ 'class': 'form-control', 'placeholder': '请输入账号!', 'required': 'required' } ) pwd = PasswordField( label="密码", validators=[ DataRequired("请输入密码!") ], description='密码', render_kw={ 'class': 'form-control', 'placeholder': '请输入密码!', 'required': 'required' } ) submit = SubmitField( "登录", render_kw={ 'class': 'btn btn-primary btn-block btn-flat' } ) def validate_account(self, field): account = field.data user = Admin.query.filter_by(name=account).count() if user == 0: raise ValidationError("账号不存在!请重新输入!!")在登录视图函数中调用登录表单LoginForm
# 登录 @admin.route('/login/', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): data = form.data admin = Admin.query.filter_by(name=data['account']).first() if not admin.check_pwd(data.get("pwd")): flash("旧密码错误,请重新输入!", "err") return redirect(url_for("admin.login")) session['admin'] = data.get("account") session['admin_id'] = admin.id adminlog = Adminlog( admin_id=admin.id, ip=request.remote_addr ) db.session.add(adminlog) db.session.commit() return redirect(request.args.get("next") or url_for('admin.index')) return render_template("admin/login.html", form=form)登录页面中调用后台登录视图函数返回来的变量form
form变量中包含管理员登录需要的字段
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>微电影管理系统</title> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <link rel="shortcut icon" href="{{ url_for('static',filename='base/images/logo.png') }}"> <link rel="stylesheet" href="{{ url_for('static',filename='admin/bootstrap/css/bootstrap.min.css') }}"> <link rel="stylesheet" href="{{ url_for('static',filename='fonts/css/font-awesome.min.css') }}"> <link rel="stylesheet" href="{{ url_for('static',filename='ionicons/css/ionicons.min.css') }}"> <link rel="stylesheet" href="{{ url_for('static',filename='admin/dist/css/AdminLTE.min.css') }}"> <link rel="stylesheet" href="{{ url_for('static',filename='admin/plugins/iCheck/square/blue.css') }}"> </head> <body class="hold-transition login-page"> <div class="login-box"> <div class="login-logo"> <a href=""><b>微电影管理系统</b></a> </div> <div class="login-box-body"> {% for msg in get_flashed_messages(category_filter=['err']) %} <p class="login-box-msg" style="color:red">{{ msg }}</p> {% endfor %} {% for msg in get_flashed_messages(category_filter=['ok']) %} <p class="login-box-msg" style="color:green">{{ msg }}</p> {% endfor %} <form method="POST" id="form-data"> {{ form.csrf_token }} <div class="form-group has-feedback"> {{ form.account }} <span class="glyphicon glyphicon-envelope form-control-feedback"></span> {% for err in form.account.errors %} <div class="col-md-12"> <font style="color:red">{{ err }}</font> </div> {% endfor %} </div> <div class="form-group has-feedback"> {{ form.pwd }} <span class="glyphicon glyphicon-lock form-control-feedback"></span> {% for err in form.pwd.errors %} <div class="col-md-12"> <font style="color:red">{{ err }}</font> </div> {% endfor %} </div> <div class="row"> <div class="col-xs-8"> </div> <div class="col-xs-4"> {{ form.submit }} </div> </div> </form> </div> </div> <script src="{{ url_for('static',filename='admin/plugins/jQuery/jQuery-2.2.0.min.js') }}"></script> <script src="{{ url_for('static',filename='admin/bootstrap/js/bootstrap.min.js') }}"></script> <script src="{{ url_for('static',filename='admin/plugins/iCheck/icheck.min.js') }}"></script> </body> </html>退出功能必须要用户登录才能有效,所以要用到登录控制装饰器
@admin.route('/logout/') @admin_login_req def logout(): session.pop("admin", None) session.pop("admin_id", None) return redirect(url_for("admin.login"))所以后台管理主页视图函数必须被登录控制装饰器和权限控制装饰器同时装饰
@admin.route('/') @admin_login_req @admin_auth def index(): return render_template("admin/index.html")由于在admin.html页面中已经导入左侧菜单部分,所以后台管理页面主页继承admin.html页面实现顶端部分和左侧菜单栏
{% extends "admin/admin.html" %} {% block content %} <section class="content-header"> <h1>微电影管理系统</h1> <ol class="breadcrumb"> <li><a href="#"><i class="fa fa-dashboard"></i> 首页</a></li> <li class="active">控制面板</li> </ol> </section> <section class="content" id="showcontent"> <div class="row"> <div class="col-md-6"> <div class="box box-primary"> <div class="box-header with-border"> <h3 class="box-title">内存使用率</h3> </div> <div class="box-body" id="meminfo" style="height:600px;"></div> </div> </div> <div class="col-md-6"> <div class="box box-primary"> <div class="box-header with-border"> <h3 class="box-title">系统设置</h3> </div> <form role="form"> <div class="box-body" style="height:600px;"> <div class="form-group"> <label for="input_speed">限制速率大小</label> <input type="text" class="form-control" id="input_speed" placeholder="请输入限制速率!" value="512"> </div> <div class="form-group"> <label for="input_mem">限制内存大小</label> <input type="text" class="form-control" id="input_mem" placeholder="请输入限制内存!" value="10m"> </div> <div class="form-group"> <label for="input_num">限制客户端数量</label> <input type="text" class="form-control" id="input_num" placeholder="请输入限制客户端数量!" value="4"> </div> <div class="form-group"> <button type="submit" class="btn btn-primary">保存并重启服务</button> </div> </div> </form> </div> </div> </div> </section> {% endblock %} {% block js %} <script src="{{ url_for('static',filename='js/echarts.min.js') }}"></script> <script> var myChart = echarts.init(document.getElementById('meminfo')); option = { backgroundColor: "white", tooltip: { formatter: "{a} <br/>{b} : {c}%" }, series: [{ name: '内存使用率', type: 'gauge', detail: { formatter: '{value}%' }, data: [{ value: 50, name: '内存使用率' }] }] }; setInterval(function () { option.series[0].data[0].value = (Math.random() * 100).toFixed(2) - 0; myChart.setOption(option, true); }, 2000); </script> <script> $(document).ready(function () { $("#g-1").addClass('active'); $("#g-1-1").addClass('active'); }); </script> {% endblock %}在app的admin目录下的forms.py文件中,定义修改密码的表单
# 修改密码表单 class PwdForm(FlaskForm): old_pwd = PasswordField( label="旧密码", validators=[ DataRequired("请输入旧密码!") ], description="旧密码", render_kw={ "class": "form-control", "placeholder": "请输入旧密码!" }, ) new_pwd = PasswordField( label="新密码", validators=[ DataRequired("请输入新密码!") ], description="新密码", render_kw={ "class": "form-control", "placeholder": "请输入新密码!" } ) summit = SubmitField( "编辑", render_kw={ "class": "btn btn-primary", } ) def validate_old_pwd(self, field): from flask import session pwd = field.data name = session.get("admin") admin = Admin.query.filter_by(name=name).first() if not admin.check_pwd(pwd): raise ValidationError("旧密码错误!")修改密码必须要登录,所以要用登录控制装饰器装饰修改密码的视图函数和权限控制装饰器进行管理用户权限判断
# 修改密码 @admin.route('/pwd/', methods=['GET', 'POST']) @admin_login_req @admin_auth def pwd(): form = PwdForm() if form.validate_on_submit(): data = form.data admin = Admin.query.filter_by(name=session.get("admin")).first() from werkzeug.security import generate_password_hash admin.pwd = generate_password_hash(data.get("new_pwd")) db.session.add(admin) db.session.commit() flash("修改密码成功,请重新登录!", "ok") return redirect(url_for("admin.logout")) return render_template("admin/pwd.html", form=form)由于在admin.html页面中已经导入左侧菜单部分,所以后台管理页面主页继承admin.html页面实现顶端部分和左侧菜单栏
{% extends "admin/admin.html" %} {% block content %} <!--内容--> <section class="content-header"> <h1>微电影管理系统</h1> <ol class="breadcrumb"> <li><a href="#"><i class="fa fa-dashboard"></i> 个人资料</a></li> <li class="active">修改密码</li> </ol> </section> <section class="content" id="showcontent"> <div class="row"> <div class="col-md-12"> <div class="box box-primary"> <div class="box-header with-border"> <h3 class="box-title">修改密码</h3> </div> <form role="form" method="post"> <div class="box-body"> <div class="form-group"> <label for="input_pwd">{{ form.old_pwd.label }}</label> {{ form.old_pwd }} <!--报错信息--> {% for err in form.old_pwd.errors %} <div class="col-md-12"> <font style="color:red">{{ err }}</font> </div> {% endfor %} </div> <div class="form-group"> <label for="input_newpwd">{{ form.new_pwd.label }}</label> {{ form.new_pwd }} <!--报错信息--> {% for err in form.new_pwd.errors %} <div class="col-md-12"> <font style="color:red">{{ err }}</font> </div> {% endfor %} </div> </div> <div class="box-footer"> {{ form.submit }} {{ form.csrf_token }} </div> </form> </div> </div> </div> </section> <!--内容--> {% endblock %}在app的admin目录下的forms.py文件中创建TagForm表单,用来保存标签的表单信息
# 标签表单 class TagForm(FlaskForm): name = StringField( label="名称", validators=[ DataRequired("请输入标签!") ], description="标签", render_kw={ "class": "form-control", "id": 'input_name', 'placeholder': '请输入标签名称!' } ) submit = SubmitField( "编辑", render_kw={ 'class': 'btn btn-primary' } )在templates目录下创建ui目录,在ui目录下创建admin_page.html页面,用来保存后台管理页面分页组件代码
{% macro page(data,url) -%} {% if data %} <ul class="pagination pagination-sm no-margin pull-right"> <li><a href="{{ url_for(url,page=1) }}">首页</a></li> {% if data.has_prev %} <li><a href="{{ url_for(url,page=data.prev_num) }}">上一页</a></li> {% else %} <li class="disabled"><a href="#">上一页</a></li> {% endif %} {% for v in data.iter_pages() %} {% if v==data.page %} <li class="active"><a href="#">{{ v }}</a></li> {% else %} <li><a href="{{ url_for(url,page=v) }}">{{ v }}</a></li> {% endif %} {% endfor %} {% if data.has_next %} <li><a href="{{ url_for(url,page=data.next_num) }}">下一页</a></li> {% else %} <li class="disabled"><a href="#">下一页</a></li> {% endif %} <li><a href="{{ url_for(url,page=data.pages) }}">尾页</a></li> </ul> {% endif %} {%- endmacro %}用控制装饰器来进行登录管理,用权限控制装饰器来进行后台管理用户判断
@admin.route("/tag/list/<int:page>/", methods=["GET"]) @admin_login_req @admin_auth def tag_list(page=None): """ 标签列表 """ if page is None: page = 1 page_data = Tag.query.order_by( Tag.addtime.desc() ).paginate(page=page, per_page=1) return render_template("admin/tag_list.html", page_data=page_data)由于在admin.html页面中已经导入左侧菜单部分,所以后台管理页面主页继承admin.html页面实现顶端部分和左侧菜单栏
导入admin_page.html来实现电影标签的分页展示
{% extends 'admin/admin.html' %} {% import 'ui/admin_page.html' as pg %} {% block content %} <!--内容--> <section class="content-header"> <h1>微电影管理系统</h1> <ol class="breadcrumb"> <li><a href="#"><i class="fa fa-dashboard"></i> 标签管理</a></li> <li class="active">标签列表</li> </ol> </section> <section class="content" id="showcontent"> <div class="row"> <div class="col-md-12"> <div class="box box-primary"> <div class="box-header"> <h3 class="box-title">标签列表</h3> <div class="box-tools"> <div class="input-group input-group-sm" style="width: 150px;"> <input type="text" name="table_search" class="form-control pull-right" placeholder="请输入关键字..."> <div class="input-group-btn"> <button type="submit" class="btn btn-default"><i class="fa fa-search"></i> </button> </div> </div> </div> </div> <div class="box-body table-responsive no-padding"> {% for msg in get_flashed_messages(category_filter=["ok"]) %} <div class="alert alert-success alert-dismissible"> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">× </button> <h4><i class="icon fa fa-check"></i>操作成功</h4> {{ msg }} </div> {% endfor %} <table class="table table-hover"> <tbody> <tr> <th>编号</th> <th>名称</th> <th>添加时间</th> <th>操作事项</th> </tr> {% for v in page_data.items %} <tr> <td>{{ v.id }}</td> <td>{{ v.name }}</td> <td>{{ v.addtime }}</td> <td> <a href="{{ url_for("admin.tag_edit",id=v.id) }}" class="label label-success">编辑</a> <a href="{{ url_for("admin.tag_del",id=v.id) }}" class="label label-danger">删除</a> </td> </tr> {% endfor %} </tbody> </table> </div> <div class="box-footer clearfix"> {{ pg.page(page_data,"admin.tag_list") }} </div> </div> </div> </div> </section> <!--内容--> {% endblock %} {% block js %} <script> $(document).ready(function () { $("#g-2").addClass('active'); $("#g-2-2").addClass('active'); }); </script> {% endblock %}注:本文转载于:https://www.cnblogs.com/renpingsheng/p/9136464.html
