之前编写了用户restful接口,但是对于想快速实现前端页面或者不会使用js前端框架的开发人员直接使用模版也是个不错的选择。
先在根目录创建templates文件夹和static文件夹
网上选择一个模版下载,我是用这个模版作为案例,把注册和登录页面放入templates文件夹,把static文件夹里的文件拷到项目static文件夹
将html模版中的静态文件路径最前面加上"/"
根目录添加views文件夹
views/auth.py
authview = Blueprint('auth',__name__,url_prefix="/html") @authview.route("/register",methods=['GET']) def pageregister(): return render_template('signup.html') @authview.route("/login",methods=['GET']) def pagelogin(): return render_template('login.html')
打开http://localhost:50057/html/register或http://localhost:50057/html/login,就能看见模版
视图中添加提交html表单的方法
views/auth.py
......
@authview.route("/register",methods=['POST']) def register(): parser = reqparse.RequestParser() parser.add_argument("username",type=str,required=True,location="form",help="username is required") parser.add_argument('password', required=True, type=str, location="form",help='password is required') parser.add_argument('email', required=False, type=str,location="form") parser.add_argument('group_id', required=False, type=int,location="form") try: args = parser.parse_args() except Exception as e: flash(e.data['message'], "error") if User.exist(username=args['username']): flash("用户名已存在", "error") return redirect(url_for("auth.register")) args.update({'password': generate_password_hash(args['password'], salt_length=8)}) User.add(args) flash('You were successfully register') return redirect(url_for("auth.pagelogin")) @authview.route("/login",methods=['POST']) def login(): parser = reqparse.RequestParser() parser.add_argument("username", type=str, required=True,location="form", help="username is required") parser.add_argument('password', required=True, type=str, location="form",help='password is required') try: args = parser.parse_args() except Exception as e: flash(e.data['message'], "error") return redirect(url_for("auth.pagelogin")) user = User.query.filter_by(username=args['username']).first() if user is None or user.delete_time is not None: flash("用户不存在",'error') return redirect(url_for("auth.pagelogin")) mpw = args['password'] ispass = check_password_hash(user.password,mpw) if not ispass: flash("密码错误",'error') return redirect(url_for("auth.pagelogin")) access_token = create_access_token(identity=user.id) response = redirect(url_for("home")) set_access_cookies(response, access_token) return response
将模版中的表单参数修改正确,并添加get_flashed_messages方法接受flash消息
templates/signin.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>DASHMIN - Bootstrap Admin Template</title> <meta content="width=device-width, initial-scale=1.0" name="viewport"> <meta content="" name="keywords"> <meta content="" name="description"> <link rel="preconnect" href="https://fonts.googleapis.com/"> <link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin=""> <link href="/static/css/css2.css" rel="stylesheet"> <link href="/static/css/all.min.css" rel="stylesheet"> <link href="/static/css/bootstrap-icons.css" rel="stylesheet"> <link href="/static/css/owl.carousel.min.css" rel="stylesheet"> <link href="/static/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet"> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/style.css" rel="stylesheet"> </head> <body> <div class="container-fluid position-relative bg-white d-flex p-0"> <div id="spinner" class="show bg-white position-fixed translate-middle w-100 vh-100 top-50 start-50 d-flex align-items-center justify-content-center"> <div class="spinner-border text-primary" style="width: 3rem; height: 3rem;" role="status"> <span class="sr-only">Loading...</span> </div> </div> <div class="container-fluid"> <div class="row h-100 align-items-center justify-content-center" style="min-height: 100vh;"> <div class="col-12 col-sm-8 col-md-6 col-lg-5 col-xl-4"> <div class="bg-light rounded p-4 p-sm-5 my-4 mx-3"> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} {% if category == 'message' %} <div class="alert alert-primary mt-3" role="alert"> {% elif category == 'error' %} <div class="alert alert-danger mt-3" role="alert"> {% else %} <div class="alert alert-primary mt-3" role="alert"> {% endif %} <ul class=flashes> {% for message in messages %} <li>{{ message[1] }}</li> {% endfor %} </ul> </div> {% endfor %} {% endif %} {% endwith %} <div class="d-flex align-items-center justify-content-between mb-3"> <a href="index1.html" class=""> <h3 class="text-primary"><i class="fa fa-hashtag me-2"></i>DASHMIN</h3> </a> <h3>登陆</h3> </div> <form action="/html/login" enctype='application/json' method="post" novalidate> <div class="form-floating mb-3"> <input type="username" class="form-control" id="floatingInput" name="username" placeholder="[email protected]" required> <label for="floatingInput">用户名</label> </div> <div class="form-floating mb-4"> <input type="password" class="form-control" id="floatingPassword" name="password" placeholder="Password" required> <label for="floatingPassword">密码</label> </div> <div class="d-flex align-items-center justify-content-between mb-4"> <div class="form-check"> <input type="checkbox" class="form-check-input" id="exampleCheck1" required> <label class="form-check-label" for="exampleCheck1">Check me out</label> </div> <a href="">Forgot Password</a> </div> <button type="submit" class="btn btn-primary py-3 w-100 mb-4">登陆</button> <p class="text-center mb-0">Don't have an Account? <a href="/html/register">注册</a></p> </form> </div> </div> </div> </div> </div> <script src="/static/js/jquery-3.4.1.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/bootstrap.bundle.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/chart.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/easing.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/waypoints.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/owl.carousel.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/moment.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/moment-timezone.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/tempusdominus-bootstrap-4.min.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/main.js" type="3029259e35d7bc1c98cd40a8-text/javascript"></script> <script src="/static/js/rocket-loader.min.js" data-cf-settings="3029259e35d7bc1c98cd40a8-|49" defer=""></script> </body> </html>
templates/signup.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>DASHMIN - Bootstrap Admin Template</title> <meta content="width=device-width, initial-scale=1.0" name="viewport"> <meta content="" name="keywords"> <meta content="" name="description"> <link rel="preconnect" href="https://fonts.googleapis.com/"> <link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin=""> <link href="/static/css/css2.css" rel="stylesheet"> <link href="/static/css/all.min.css" rel="stylesheet"> <link href="/static/css/bootstrap-icons.css" rel="stylesheet"> <link href="/static/css/owl.carousel.min.css" rel="stylesheet"> <link href="/static/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet"> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/style.css" rel="stylesheet"> </head> <body> <div class="container-fluid position-relative bg-white d-flex p-0"> <div id="spinner" class="show bg-white position-fixed translate-middle w-100 vh-100 top-50 start-50 d-flex align-items-center justify-content-center"> <div class="spinner-border text-primary" style="width: 3rem; height: 3rem;" role="status"> <span class="sr-only">Loading...</span> </div> </div> <div class="container-fluid"> <div class="row h-100 align-items-center justify-content-center" style="min-height: 100vh;"> <div class="col-12 col-sm-8 col-md-6 col-lg-5 col-xl-4"> <div class="bg-light rounded p-4 p-sm-5 my-4 mx-3"> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} {% if category == 'message' %} <div class="alert alert-primary mt-3" role="alert"> {% elif category == 'error' %} <div class="alert alert-danger mt-3" role="alert"> {% else %} <div class="alert alert-primary mt-3" role="alert"> {% endif %} <ul class=flashes> {% for message in messages %} <li>{{ message[1] }}</li> {% endfor %} </ul> </div> {% endfor %} {% endif %} {% endwith %} <div class="d-flex align-items-center justify-content-between mb-3"> <a href="index1.html" class=""> <h3 class="text-primary"><i class="fa fa-hashtag me-2"></i>DASHMIN</h3> </a> <h3>注册</h3> </div> <form action="/html/register" method="post" class="needs-validation" novalidate> <div class="form-floating mb-3"> <input type="text" class="form-control" id="floatingText" name="username" placeholder="jhondoe" required> <label for="floatingText">用户名</label> </div> <div class="form-floating mb-3"> <input type="email" class="form-control" id="floatingInput" name="email" placeholder="[email protected]" required> <label for="floatingInput">Email</label> </div> <div class="form-floating mb-4"> <input type="password" class="form-control" id="floatingPassword" name="password" placeholder="Password" required> <label for="floatingPassword">密码</label> </div> <div class="d-flex align-items-center justify-content-between mb-4"> <div class="form-check"> <input type="checkbox" class="form-check-input" id="exampleCheck1" required> <label class="form-check-label" for="exampleCheck1">Check me out</label> </div> <a href="">Forgot Password</a> </div> <button type="submit" class="btn btn-primary py-3 w-100 mb-4">注册</button> <p class="text-center mb-0">Already have an Account? <a href="/html/login">登陆</a></p> </form> </div> </div> </div> </div> </div> <script src="/static/js/jquery-3.4.1.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/bootstrap.bundle.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/chart.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/easing.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/waypoints.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/owl.carousel.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/moment.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/moment-timezone.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/tempusdominus-bootstrap-4.min.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/main.js" type="51e0fbf48a5089fe5b05817f-text/javascript"></script> <script src="/static/js/rocket-loader.min.js" data-cf-settings="51e0fbf48a5089fe5b05817f-|49" defer=""></script></body> </html>
之后在页面注册就能成功并显示相关flash信息
登陆后需要跳转首页,接下来添加首页路由及模版,模版根据需要拷到templates文件夹内
app.py
...... @app.route("/") @login_required def home(): return render_template("home.html",user=current_user)
改写login_required方法
auth.py
def login_required(fn): @wraps(fn) def wrapper(*args, **kwargs): try: verify_jwt_in_request() except Exception as e: flash(str(e), "error") return redirect(url_for("auth.login")) return fn(*args, **kwargs) return wrapper
这样首页就成功显示,然后加入登出路由
views/auth.py
...... @authview.route("/logout",methods=['GET']) def logout(): response = redirect(url_for("auth.pagelogin")) unset_jwt_cookies(response) flash('You were logout') return response
templates/home.html
...... <a href="/html/logout" class="dropdown-item">Log Out</a>
登出功能也实现了
接下来根据需要修改首页,将中间content部分改为jinja2模版语句{% block content %}{% endblock %},并改名为base.html
templates/base.html
<html lang="en"><head> <meta charset="utf-8"> <title>DASHMIN - Bootstrap Admin Template</title> <meta content="width=device-width, initial-scale=1.0" name="viewport"> <meta content="" name="keywords"> <meta content="" name="description"> <link rel="preconnect" href="https://fonts.googleapis.com/"> <link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin=""> <link href="/static/css/css2.css" rel="stylesheet"> <link href="/static/css/all.min.css" rel="stylesheet"> <link href="/static/css/bootstrap-icons.css" rel="stylesheet"> <link href="/static/css/owl.carousel.min.css" rel="stylesheet"> <link href="/static/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet"> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/style.css" rel="stylesheet"> </head> <body> <div class="container-fluid position-relative bg-white d-flex p-0"> <div id="spinner" class="bg-white position-fixed translate-middle w-100 vh-100 top-50 start-50 d-flex align-items-center justify-content-center"> <div class="spinner-border text-primary" style="width: 3rem; height: 3rem;" role="status"> <span class="sr-only">Loading...</span> </div> </div> <div class="sidebar pe-4 pb-3"> <nav class="navbar bg-light navbar-light"> <a href="index1.html" class="navbar-brand mx-4 mb-3"> <h3 class="text-primary"><i class="fa fa-hashtag me-2"></i>我的站点</h3> </a> <div class="navbar-nav w-100"> <div class="nav-item dropdown"> <a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown"><i class="fa fa-laptop me-2"></i>系统管理</a> <div class="dropdown-menu bg-transparent border-0"> <a href="/html/user/list" class="dropdown-item">用户管理</a> <a href="/html/group/list" class="dropdown-item">分组管理</a> </div> </div> </div> </nav> </div> <div class="content"> <nav class="navbar navbar-expand bg-light navbar-light sticky-top px-4 py-0"> <div class="navbar-nav align-items-center ms-auto"> <div class="nav-item dropdown"> <a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown"> <span class="d-none d-lg-inline-flex">{{ user.username }}</span> </a> <div class="dropdown-menu dropdown-menu-end bg-light border-0 rounded-0 rounded-bottom m-0"> <a href="#" class="dropdown-item">My Profile</a> <a href="#" class="dropdown-item">Settings</a> <a href="/html/logout" class="dropdown-item">Log Out</a> </div> </div> </div> </nav> <div class="container-fluid pt-4 px-4"> {% block content %}{% endblock %} </div> <div class="container-fluid pt-4 px-4"> <div class="bg-light rounded-top p-4"> <div class="col-12 col-sm-6 text-center text-sm-start"> Copyright © 2022.Company name All rights reserved. </div> <div class="col-12 col-sm-6 text-center text-sm-end"> </div> </div> </div> </div> </div> <a href="#" class="btn btn-lg btn-primary btn-lg-square back-to-top" style="display: none;"><i class="bi bi-arrow-up"></i></a> <script src="/static/js/jquery-3.4.1.min.js" type="text/javascript"></script> <script src="/static/js/bootstrap.bundle.min.js" type="text/javascript"></script> <script src="/static/js/chart.min.js" type="text/javascript"></script> <script src="/static/js/easing.min.js" type="text/javascript"></script> <script src="/static/js/waypoints.min.js" type="text/javascript"></script> <script src="/static/js/owl.carousel.min.js" type="text/javascript"></script> <script src="/static/js/moment.min.js" type="text/javascript"></script> <script src="/static/js/moment-timezone.min.js" type="text/javascript"></script> <script src="/static/js/tempusdominus-bootstrap-4.min.js" type="text/javascript"></script> <script src="/static/js/main.js" type="text/javascript"></script> </body></html>
新建templates/home.html,使用父模版,并重写content不分
{% extends 'base.html' %} {% block content %} <div class="row vh-100 bg-light rounded align-items-center justify-content-center mx-0"> <div class="col-md-6 text-center"> <h3>This is blank page</h3> </div> </div> {% endblock %}
接下来编写用户列表的路由
views/user.py
userview = Blueprint('user',__name__,url_prefix="/html/user") class Customdatatime(fields.DateTime): def __init__(self): super(Customdatatime, self).__init__() def format(self, value): return value.strftime('%Y-%m-%d %H:%M:%S') user_fields = { 'id': fields.Integer, 'username': fields.String, 'nickname': fields.String, 'email': fields.String, 'group_id': fields.Integer, 'group': fields.Raw, '_create_time': Customdatatime, 'update_time': Customdatatime, } @route_meta("用户列表", "user.list") @userview.route("/list",methods=['GET']) @login_required def list(): users = User.getall() for user in users: user.group = Group.getone(user.group_id) groups = Group.getall() return render_template('user.html',data=marshal(users, user_fields),user=current_user,groups=marshal(groups,group_fields))
根据需要将table模版放入templates,并修改数据
{% extends 'base.html' %} {% block content %} <div class="row g-4"> <div class="col-sm-12"> <div class="bg-light rounded h-100 p-4"> <div class="row"> <h6 class="mb-4 col-8">Basic Table</h6> <span class="col-4"><a class="btn btn-primary" style="float: right" href="#" role="button" data-bs-toggle="modal" data-bs-target="#exampleModal">新增</a></span> </div> <table class="table"> <thead> <tr> <th scope="col">#</th> <th scope="col">username</th> <th scope="col">nickname</th> <th scope="col">email</th> <th scope="col">group</th> <th scope="col">_create_time</th> <th scope="col" class="text-center">操作</th> </tr> </thead> <tbody> {% for item in data %} <tr> <td>{{item.id}}</td> <td>{{item.username}}</td> <td>{{item.nickname}}</td> <td>{{item.email}}</td> <td>{{item.group.name}}</td> <td>{{item._create_time}}</td> <td class="text-center"> <a class="btn btn-primary btn-sm" style="margin-right: 20px;" href="#" role="button" data-bs-toggle="modal" data-bs-target="#exampleModal2" onclick="edit({{item.id}})">编辑</a> <a class="btn btn-danger btn-sm" style="margin-left: 20px;" href="#" role="button" data-bs-toggle="modal" data-bs-target="#exampleModal3" onclick="delete1({{item.id}})">删除</a> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> {% endblock %}
这样就能显示列表了
然后编写新增用户的路由
views/user.py
......
@route_meta("新增用户", "user.add") @userview.route("/add",methods=['POST']) @login_required def add(): parser = reqparse.RequestParser() parser.add_argument("id", type=int,location="form", required=False) parser.add_argument("username", type=str, location="form",required=True, help="username is required") parser.add_argument("nickname", type=str, location="form",required=True, help="nickname is required") parser.add_argument('password', required=True, location="form",type=str, help='password is required') parser.add_argument('email', required=False, location="form",type=str) parser.add_argument('group_id', required=False, location="form",type=int, default=2) try: args = parser.parse_args() except Exception as e: flash(e.data['message'], "error") return redirect(url_for("user.list")) if User.exist(username=args['username']): flash("用户名已存在","error") else: args.update({'password': generate_password_hash(args['password'], salt_length=8)}) User.add(args) flash("用户添加成功") return redirect(url_for("user.list"))
并给模版添加模态框表单,并添加get_flashed_messages方法接受flash消息显示提示信息
templates/user.html
<span class="col-4"><a class="btn btn-primary" style="float: right" href="#" role="button" data-bs-toggle="modal" data-bs-target="#exampleModal">新增</a></span> ...... <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel">新增用户</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form action="/html/user/add" enctype='application/json' method="post" class="needs-validation" novalidate> <div class="mb-3"> <label for="message-text" class="col-form-label">username:</label> <input type="text" class="form-control" id="username" name="username" required> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">password:</label> <input type="password" class="form-control" id="password" name="password" required> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">nickname:</label> <input type="text" class="form-control" id="nickname" name="nickname" required> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">email:</label> <input type="text" class="form-control" id="email" name="email" required> </div> <div class="mb-3"> <label for="message-select" class="col-form-label">group:</label> <select class="form-select" id="group" aria-label="group" name="group_id" required> <option selected>Open this select menu</option> {% for item in groups %} <option value="{{ item.id }}">{{ item.name }}</option> {% endfor %} </select> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary">save</button> </div> </form> </div> </div> </div>
templates/base.html
......
<div class="container-fluid pt-4 px-4"> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} {% if category == 'message' %} <div class="alert alert-primary mt-3 alert-dismissible" role="alert"> {% elif category == 'error' %} <div class="alert alert-danger mt-3 alert-dismissible" role="alert"> {% else %} <div class="alert alert-primary mt-3 alert-dismissible" role="alert"> {% endif %} <button type="button" class="btn-close" data-bs-dismiss="alert"></button> <ul class=flashes> {% for message in messages %} <li>{{ message[1] }}</li> {% endfor %} </ul> </div> {% endfor %} {% endif %} {% endwith %} {% block content %}{% endblock %} </div>
这样页面上一个添加用户的功能就完成了
用户的改查删也是同样的逻辑来编写,完整代码如下
views/user.py
from flask import Blueprint, render_template, flash, redirect, url_for, jsonify from flask_jwt_extended import current_user from flask_restful import marshal, fields, reqparse from werkzeug.security import generate_password_hash from auth import login_required, group_required from models.group import Group from models.user import User from router import route_meta from views.groupview import group_fields userview = Blueprint('user',__name__,url_prefix="/html/user") class Customdatatime(fields.DateTime): def __init__(self): super(Customdatatime, self).__init__() def format(self, value): return value.strftime('%Y-%m-%d %H:%M:%S') user_fields = { 'id': fields.Integer, 'username': fields.String, 'nickname': fields.String, 'email': fields.String, 'group_id': fields.Integer, 'group': fields.Raw, '_create_time': Customdatatime, 'update_time': Customdatatime, } @route_meta("用户列表", "user.list") @userview.route("/list",methods=['GET']) @login_required def list(): users = User.getall() for user in users: user.group = Group.getone(user.group_id) groups = Group.getall() return render_template('user.html',data=marshal(users, user_fields),user=current_user,groups=marshal(groups,group_fields)) @userview.route("/<uid>",methods=['GET']) @login_required def info(uid): user = User.getone(uid) return jsonify({ "code": 0, "msg": "success", "data": marshal(user, user_fields) }) @route_meta("新增用户", "user.add") @userview.route("/add",methods=['POST']) @login_required def add(): parser = reqparse.RequestParser() parser.add_argument("id", type=int,location="form", required=False) parser.add_argument("username", type=str, location="form",required=True, help="username is required") parser.add_argument("nickname", type=str, location="form",required=True, help="nickname is required") parser.add_argument('password', required=True, location="form",type=str, help='password is required') parser.add_argument('email', required=False, location="form",type=str) parser.add_argument('group_id', required=False, location="form",type=int, default=2) try: args = parser.parse_args() except Exception as e: flash(e.data['message'], "error") return redirect(url_for("user.list")) if User.exist(username=args['username']): flash("用户名已存在","error") else: args.update({'password': generate_password_hash(args['password'], salt_length=8)}) User.add(args) flash("用户添加成功") return redirect(url_for("user.list")) @route_meta("编辑用户", "user.edit") @userview.route("/edit",methods=['POST']) @login_required def edit(): parser = reqparse.RequestParser() parser.add_argument("id", required=True, type=int, location="form",help="id is required") parser.add_argument("username", type=str, required=True,location="form", help="username is required") parser.add_argument("nickname", type=str, required=True,location="form", help="nickname is required") parser.add_argument('email', required=False, type=str,location="form") parser.add_argument('group_id', required=False, type=int, location="form") try: args = parser.parse_args() except Exception as e: flash(e.data['message'], "error") return redirect(url_for("user.list")) if not User.exist(id=args['id']): flash("用户不存在", "error") return redirect(url_for("user.list")) else: User.edit(args) flash("用户编辑成功") return redirect(url_for("user.list")) @route_meta("删除用户", "user.delete") @userview.route("/delete",methods=['POST']) @login_required def delete(): parser = reqparse.RequestParser() parser.add_argument("id", required=True, type=int, location="form", help="id is required") try: args = parser.parse_args() except Exception as e: flash(e.data['message'], "error") uid = args.get('id') User.remove(uid) flash("用户删除成功") return redirect(url_for("user.list"))
templates/user.html
{% extends 'base.html' %} {% block content %} <div class="row g-4"> <div class="col-sm-12"> <div class="bg-light rounded h-100 p-4"> <div class="row"> <h6 class="mb-4 col-8">Basic Table</h6> <span class="col-4"><a class="btn btn-primary" style="float: right" href="#" role="button" data-bs-toggle="modal" data-bs-target="#exampleModal">新增</a></span> </div> <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel">新增用户</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form action="/html/user/add" enctype='application/json' method="post" class="needs-validation" novalidate> <div class="mb-3"> <label for="message-text" class="col-form-label">username:</label> <input type="text" class="form-control" id="username" name="username" required> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">password:</label> <input type="password" class="form-control" id="password" name="password" required> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">nickname:</label> <input type="text" class="form-control" id="nickname" name="nickname" required> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">email:</label> <input type="text" class="form-control" id="email" name="email" required> </div> <div class="mb-3"> <label for="message-select" class="col-form-label">group:</label> <select class="form-select" id="group" aria-label="group" name="group_id" required> <option selected>Open this select menu</option> {% for item in groups %} <option value="{{ item.id }}">{{ item.name }}</option> {% endfor %} </select> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary">save</button> </div> </form> </div> </div> </div> <table class="table"> <thead> <tr> <th scope="col">#</th> <th scope="col">username</th> <th scope="col">nickname</th> <th scope="col">email</th> <th scope="col">group</th> <th scope="col">_create_time</th> <th scope="col" class="text-center">操作</th> </tr> </thead> <tbody> {% for item in data %} <tr> <td>{{item.id}}</td> <td>{{item.username}}</td> <td>{{item.nickname}}</td> <td>{{item.email}}</td> <td>{{item.group.name}}</td> <td>{{item._create_time}}</td> <td class="text-center"> <a class="btn btn-primary btn-sm" style="margin-right: 20px;" href="#" role="button" data-bs-toggle="modal" data-bs-target="#exampleModal2" onclick="edit({{item.id}})">编辑</a> <a class="btn btn-danger btn-sm" style="margin-left: 20px;" href="#" role="button" data-bs-toggle="modal" data-bs-target="#exampleModal3" onclick="delete1({{item.id}})">删除</a> </td> </tr> {% endfor %} </tbody> </table> <div class="modal fade" id="exampleModal2" tabindex="-1" aria-labelledby="exampleModalLabel2" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel2">编辑用户</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form action="/html/user/edit" enctype='application/json' method="post" class="needs-validation" novalidate> <div class="mb-3" style="display: none;"> <label for="message-text" class="col-form-label">id:</label> <input type="text" class="form-control" id="editid" name="id"> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">username:</label> <input type="text" class="form-control" id="editusername" name="username"> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">password:</label> <input type="password" class="form-control" id="editpassword" name="password"> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">nickname:</label> <input type="text" class="form-control" id="editnickname" name="nickname"> </div> <div class="mb-3"> <label for="message-text" class="col-form-label">email:</label> <input type="text" class="form-control" id="editemail" name="email"> </div> <div class="mb-3"> <label for="message-select" class="col-form-label">group:</label> <select class="form-select" id="editgroup" aria-label="group" name="group_id" required> <option selected>Open this select menu</option> {% for item in groups %} <option value="{{ item.id }}">{{ item.name }}</option> {% endfor %} </select> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary">save</button> </div> </form> </div> </div> </div> <div class="modal fade" id="exampleModal3" tabindex="-1" aria-labelledby="exampleModalLabel3" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel3">删除警告</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form action="/html/user/delete" enctype='application/json' method="post" novalidate> <div class="mb-3" style="display: none;"> <label for="message-text" class="col-form-label">id:</label> <input type="text" class="form-control" id="delid" name="id"> </div> 是否确认删除 </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="submit" class="btn btn-danger">删除</button> </div> </form> </div> </div> </div> </div> </div> </div> <script> // 如果验证不通过禁止提交表单 (function() { 'use strict'; window.addEventListener('load', function() { // 获取表单验证样式 var forms = document.getElementsByClassName('needs-validation'); // 循环并禁止提交 var validation = Array.prototype.filter.call(forms, function(form) { form.addEventListener('submit', function(event) { if (form.checkValidity() === false) { event.preventDefault(); event.stopPropagation(); } form.classList.add('was-validated'); }, false); }); }, false); })(); function edit(id) { var request = new XMLHttpRequest(); // 创建XMLHttpRequest对象 //ajax是异步的,设置回调函数 request.onreadystatechange = function () { // 状态发生变化时,函数被回调 if (request.readyState === 4) { // 成功完成 // 判断响应状态码 if (request.status === 200) { // 成功,通过responseText拿到响应的文本: const data = JSON.parse(request.responseText).data console.log(data) document.getElementById('editid').value=id; document.getElementById('editusername').value=data.username; document.getElementById('editpassword').value=data.password; document.getElementById('editnickname').value=data.nickname; document.getElementById('editemail').value=data.email; document.getElementById('editgroup').value=data.group_id; } else { // 失败,根据响应码判断失败原因: console.log(request.responseText) } } else { // HTTP请求还在继续... } } // 发送请求: request.open('GET', '/html/user/'+id); request.send();//到这一步,请求才正式发出 } function delete1(id) { document.getElementById('delid').value=id; } </script> {% endblock %}
这样一个完整的用户增删改查的页面基本完成,分组页面以及其他的页面管理功能也是按照同样的逻辑来编写,这个方式总体来说上手比vue、react等前端框架简单,但是如果要很强的用户体验还是建议使用前端框架。下篇文章讲介绍vue对注册登陆借口的处理,敬请期待。
标签:parser,args,flask,模版,required,天用,add,user,id From: https://www.cnblogs.com/zerotest/p/16797719.html