概述
- 模型 Admin
- 表单 PwdForm
- 请求方法 GET POST
- 访问控制 @admin_login_req
- 涉及文件
- movie2101/app/templates/admin/login.html 修改密码后会跳转到登录界面
- movie2101/app/templates/admin/admin.html 当前用户信息
- movie2101/app/admin/views.py 密码修改视图函数
- movie2101/app/admin/forms.py 密码修改表单
- movie2101/app/templates/admin/pwd.html 密码修改页面
可以进一步完善处:
- 防止新修改密码和就密码相同
- 如何给用户重置一个默认密码
难重点
旧密码的检查和新密码的生成
代码展示
密码修改表单
movie2101/app/admin/forms.py
class PwdForm(FlaskForm): old_pwd = PasswordField( label="旧密码", validators=[ DataRequired("请输入旧密码~~!"), # Length("密码长度必须大于%(max)d且小于%(min)d") ], description="旧密码", render_kw={ # 设置生成前端"账号标签"对应的html属性 "class": "form-control", "placeholder": "请输入密码!", } ) new_pwd = PasswordField( label="新密码", validators=[ DataRequired("请输入新密码~~!"), # Length("密码长度必须大于%(max)d且小于%(min)d") ], description="新密码", render_kw={ # 设置生成前端"账号标签"对应的html属性 "class": "form-control", "placeholder": "请输入新密码!", } ) re_new_pwd = PasswordField( label="确认密码", validators=[ DataRequired("请再次输入新密码~~!"), EqualTo("new_pwd", message="两次密码不一致,请重新输入!") # Length("密码长度必须大于%(max)d且小于%(min)d") ], description="确认密码", render_kw={ # 设置生成前端"账号标签"对应的html属性 "class": "form-control", "placeholder": "请再次输入密码!", } ) submit = SubmitField( "修改", render_kw={ # 设置生成前端"账号标签"对应的html属性 "class": "btn btn-primary", } ) def validate_old_pwd(self, field): # 也可在视图函数中实现 from flask import session pwd = field.data name = session["admin"] admin = Admin.query.filter_by(name=name).first() if not admin.check_pwd(pwd): raise ValidationError("旧密码错误!")
密码修改视图函数
movie2101/app/admin/views.py
@admin.route("/pwd", methods=["GET", "POST"]) @admin_login_req def pwd(): form = PwdForm() if form.validate_on_submit(): data = form.data admin = Admin.query.filter_by(name=session["admin"]).first() from werkzeug.security import generate_password_hash admin.pwd = generate_password_hash(data["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)
密码修改页面
movie2101/app/templates/admin/pwd.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> {% 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 %} {% for msg in get_flashed_messages(category_filter=["err"]) %} <div class="alert alert-danger alert-dismissible"> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4><i class="icon fa fa-ban"></i> 操作失败!</h4> {{ msg }} </div> {% endfor %} <form role="form" method="post" novalidate enctype="multipart/form-data"> <div class="box-body"> <div class="form-group"> <label for="input_pwd">{{ form.old_pwd.label }}</label> {{ form.old_pwd }} </div> {% for err in form.old_pwd.errors %} <div style="color: red" class="col-md-12">{{ err }}</div> {% endfor %} <div class="form-group"> <label for="input_newpwd">{{ form.new_pwd.label }}</label> {{ form.new_pwd }} </div> {% for err in form.new_pwd.errors %} <div style="color: red" class="col-md-12">{{ err }}</div> {% endfor %} <div class="form-group"> <label for="input_newpwd">{{ form.re_new_pwd.label }}</label> {{ form.re_new_pwd }} </div> {% for err in form.re_new_pwd.errors %} <div style="color: red" class="col-md-12">{{ err }}</div> {% endfor %} </div> <div class="box-footer"> {{ form.csrf_token }} {{ form.submit }} </div> </form> </div> </div> </div> </section> {% endblock %}
当前用户信息
movie2101/app/templates/admin/admin.html
<!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/dist/css/skins/_all-skins.min.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='admin/plugins/datepicker/datepicker3.css') }}/"> <style> *{ font-family:"Microsoft YaHei"; } .table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th{ vertical-align:middle; text-align:center; } </style> {% block css %} {% endblock %} </head> <body class="hold-transition skin-blue sidebar-mini"> <div class="wrapper"> <header class="main-header"> <a href="{{ url_for('admin.index') }}" class="logo"> <span class="logo-mini"><img src="{{ url_for('static', filename='base/images/logo.png') }}" style="height:40px;width:40px;">电影系统</span> <span class="logo-lg"><img src="{{ url_for('static', filename='base/images/logo.png') }}" style="height:40px;width:40px;">微电影管理系统</span> </a> <nav class="navbar navbar-static-top"> <a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button"> <span class="sr-only">下拉菜单</span> </a> <div class="navbar-custom-menu"> <ul class="nav navbar-nav"> <li class="dropdown user user-menu"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> <img src="{{ url_for('static', filename='admin/dist/img/user2-160x160.jpg') }}" class="user-image" alt="User Image"> <span class="hidden-xs">{{ session["admin"] }}</span> </a> <ul class="dropdown-menu"> <li class="user-header"> <img src="{{ url_for('static', filename='admin/dist/img/user2-160x160.jpg') }}" class="img-circle" alt="User Image"> <p> {{ session["admin"] }} <small>2017-06-01</small> </p> </li> <li class="user-footer"> <div class="pull-left"> <a href="{{ url_for('admin.pwd') }}" class="btn btn-default btn-flat">修改密码</a> </div> <div class="pull-right"> <a href="{{ url_for('admin.login') }}" class="btn btn-default btn-flat">退出系统</a> </div> </li> </ul> </li> </ul> </div> </nav> </header> <aside class="main-sidebar"> <section class="sidebar"> <div class="user-panel"> <div class="pull-left image"> <img src="{{ url_for('static', filename='admin/dist/img/user2-160x160.jpg') }}" class="img-circle" alt="User Image"> </div> <div class="pull-left info"> <p>用户{{ session["admin"] }}</p> <a href="#"><i class="fa fa-circle text-success"></i> 在线</a> </div> </div> <form action="#" method="get" class="sidebar-form"> <div class="input-group"> <input type="text" name="q" class="form-control" placeholder="搜索..."> <span class="input-group-btn"> <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i> </button> </span> </div> </form> <!--管理菜单--> {% include 'admin/grid.html' %} <!--管理菜单--> </section> </aside> <div class="content-wrapper"> <!--内容--> {% block content %} {% endblock %} <!--内容--> </div> <footer class="main-footer"> <div class="pull-right hidden-xs"> <b>版本</b> 1.0 </div> <strong>版权 © 2017-2018 归<a href="">xxx</a>.</strong> 所有 </footer> <div class="control-sidebar-bg"></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/slimScroll/jquery.slimscroll.min.js') }}"></script> <script src="{{ url_for('static', filename='admin/plugins/fastclick/fastclick.js') }}"></script> <script src="{{ url_for('static', filename='admin/dist/js/app.min.js') }}"></script> <script src="{{ url_for('static', filename='admin/dist/js/demo.js') }}"></script> <script src="//cdn.bootcss.com/holder/2.9.4/holder.min.js"></script> <script src="{{ url_for('static', filename='admin/plugins/datepicker/bootstrap-datepicker.js') }}"></script> <script src="{{ url_for('static', filename='admin/plugins/datepicker/locales/bootstrap-datepicker.zh-CN.js') }}" charset="UTF-8"></script> {% block js %} {% endblock %} </body> </html>
页面效果:
登录页面添加flash提示
movie2101/app/templates/admin/login.html
<!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=["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 %} {% for msg in get_flashed_messages(category_filter=["err"]) %} <div class="alert alert-danger alert-dismissible"> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4><i class="icon fa fa-ban"></i> 操作失败!</h4> {{ msg }} </div> {% endfor %} <form method="POST" id="form-data" novalidate> <div class="form-group has-feedback"> <!-- <input name="user" type="text" class="form-control" placeholder="请输入账号!">--> {{ form.account }} <span class="glyphicon glyphicon-envelope form-control-feedback"></span> {% for err in form.account.errors %} <div style="color: red" class="col-md-12" id="input_user">{{ err }}</div> {% endfor %} </div> <div class="form-group has-feedback"> <!-- <input name="pwd" type="password" class="form-control" placeholder="请输入密码!">--> {{ form.pwd }} <span class="glyphicon glyphicon-lock form-control-feedback"></span> {% for err in form.pwd.errors %} <div style="color: red" class="col-md-12">{{ err }}</div> {% endfor %} </div> <div class="row"> <div class="col-xs-8"> </div> <div class="col-xs-4"> <!-- <a id="btn-sub" type="submit" class="btn btn-primary btn-block btn-flat">登录</a>--> {{ form.submit }} {{ form.csrf_token }} </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>
页面效果: