首页 > 其他分享 >3天用flask搭建平台实战教程四:直接使用现成模版写出后台

3天用flask搭建平台实战教程四:直接使用现成模版写出后台

时间:2022-10-17 02:11:06浏览次数:91  
标签:parser args flask 模版 required 天用 add user id

之前编写了用户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

相关文章

  • Flask学习笔记(十三)-Flask_WTF实现表单
    一、Web表单Web表单是Web应用程序的基本功能。它是HTML页面中负责数据采集的部件。表单有三个部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页......
  • flask搭建平台入门教程三:增删改查接口及权限校验(前后端分离)
    用户注册登录实现后,下一步编写查询用户列表接口,使用flask_restful的marshal方法来生成字段数据,加上之前编写的login_requiredfromflaskimportBlueprint,jsonifyfrom......
  • flask搭建平台入门教程二:用户注册和登录
    这一篇主要实现用户注册和登录编写接口并设置URL根目录添加api文件夹,添加auth.py注册auth蓝图为根路径fromflaskimportBlueprint,jsonifyauthbp=Blueprint('au......
  • flask搭建平台入门教程一:配置数据库
    flask是什么?flask可以做什么这里就不说了,百度一下即可,这篇文章主要是手把手带你使用flask搭建一个简单的注册、登陆、以及用户权限管理模块。首先需要创建一个FLASK项......
  • flask-信号
    flask信号Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为。#pip3installblinker1.内置信号request_started=_signals......
  • Flask 学习-91.使用 gunicorn 部署 flask
    前言flask启动访问平常开发的时候可以用命令行flaskrun运行,正式部署到线上环境不会这样用。Gunicorn环境准备Web框架致力于如何生成HTML代码,而Web服务器用于处理和响......
  • 用flask搭建管理平台
    flask是什么?flask可以做什么这里就不说了,百度一下即可,这篇文章主要是手把手带你使用flask搭建一个简单的注册、登陆、以及用户权限管理模块。在pycharm上创建新的flask......
  • Python Flask-SocketIO没有启动成功
    背景最近想做websocket服务端,发现Flask已提供第三方库;尝试使用后,发现前端也必须使用SocketIO,不太适用,所以放弃。 问题WARNINGininit:WebSockettransportnotavai......
  • Python Flask 返回html文件
    1、在templates文件夹建立一个html文件<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>Index</title></head><body><h2>This is i......
  • Python Flask报错:TypeError: 'NoneType' object is not subscriptable
    问题:用Flask写了一个请求,用Jmeter请求时报错;但在postman中参数发送,可以成功返回数据以及正常状态码200; 分析:request以json形式发送post请求时,需要headers 解决:he......