Flask项目实战——2—(后台用户登录验证、错误登录信息渲染到前端界面、钩子函数和装饰器、CSRF验证保护、用户名渲染和注销功能、模板继承)

1、后台用户登录验证

1、用户登录的操作是post提交方式:
在这里插入图片描述
将后台用户提交的form表单信息收集:创建cms/forms.py文件

后台登录用户表单收集文件:forms.py文件

# -*- encoding: utf-8 -*-
"""
@File    : forms.py
@Time    : 2020/5/11 10:00
@Author  : chen

"""
# forms表单信息
from wtforms import Form, StringField, IntegerField
from wtforms.validators import Email, InputRequired, Length


class LoginForm(Form):
    email = StringField(validators=[Email(message="请输入正确的邮箱"),  InputRequired(message="请输入邮箱")])
    password = StringField(validators=[Length(3, 15, message='请输入正确长度的密码')])
    remember = IntegerField()                # 记住cookie操作  赋值为0或1

forms.py文件收集到的后台登录用户字段信息提交至views.py文件

验证登录用户表单信息是否匹配数据库中的信息:views.py

# -*- encoding: utf-8 -*-
"""
@File    : views.py
@Time    : 2020/5/11 9:59
@Author  : chen

"""
# 蓝图文件:实现模块化应用,应用可以分解成一系列的蓝图   后端的类视图函数写在这个文件
from flask import Blueprint, render_template, views, session   # 定义类视图,显示模板文件
from flask import request, redirect, url_for          # 页面跳转redirect   request请求收集
# 导入form表单   .forms代表同级目录下的forms.py
from .forms import LoginForm

# 导入模型  .models代表同级目录下的models.py
from .models import CMS_User

cms_bp = Blueprint("cms", __name__, url_prefix='/cms/')     # URL前缀url_prefix


@cms_bp.route("/")                                          # 后台界面
def index():
    return "cms index:后端类视图文件"


# 定义类视图,显示模板文件
class LoginView(views.MethodView):
    def get(self):
        return render_template("cms/cms_login.html")
    
    # 用户登录操作验证
    def post(self):
        # 收集表单信息
        login_form = LoginForm(request.form)
        if login_form.validate():
            # 数据库验证
            email = login_form.email.data
            password = login_form.password.data
            remember = login_form.remember.data
            
            # 查询数据库中的用户信息
            user = CMS_User.query.filter_by(email=email).first()    # 邮箱唯一,用于查询验证用户
            if user and user.check_password(password):              # 验证用户和密码是否都正确
                session['user_id'] = user.id                        # 查询到用户数据时,保存session的id到浏览器
                if remember:                                        # 如果用户点击了remember选择,在浏览器中进行数据持久化
                    session.permanent = True                        # 数据持久化,默认31天,需要设置session_key在config.py中
            
                # 登录成功,跳转到后台首页
                return redirect(url_for('cms.index'))               # 在蓝图中必须加cms   跳转到index方法
            else:
                return "邮箱或密码错误"                              # 登录出错,返回结果
        else:
            print(login_form.errors)
            return "表单验证错误"
         
    
# 添加登录路由
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login'))    # view_func 命名操作名字,"/login/"路由地址

views.py文件中有一个密码验证的方法check_password(password),需要在模型文件models.py中进行添加;
验证用户信息之后,包含session信息的加密方式,需要设置session_key在config.py中。

模型文件:models.py

# -*- encoding: utf-8 -*-
"""
@File    : models.py
@Time    : 2020/5/11 10:00
@Author  : chen

"""
# 定义后端用户模型
from exts import db
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash         # 导入密码加密,解密方法的库


class CMS_User(db.Model):
    __tablename__ = 'cms_user'
    
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)           # 主键  自增
    username = db.Column(db.String(150), nullable=False)                       # 非空
    # password = db.Column(db.String(150), nullable=False)
    _password = db.Column(db.String(150), nullable=False)                      # 密码加密操作修改字段
    email = db.Column(db.String(50), nullable=False, unique=True)              # 非空、唯一
    join_time = db.Column(db.DateTime, default=datetime.now)                   # 默认当前时间
    
    # 修改密码加密操作中的字段,在manage.py映射数据库时候,使用字段还是保持相同
    def __init__(self, username, password, email):
        self.username = username
        self.password = password         # 调用该方法 返回下面的self._password数值,
        self.email = email
    
    # 密码加密操作
    @property
    def password(self):                   # 密码取值
        return self._password

    @password.setter                      # 密码加密
    def password(self, raw_password):
        self._password = generate_password_hash(raw_password)

    # 用于验证后台登录密码是否和数据库一致,raw_password是后台登录输入的密码
    def check_password(self, raw_password):
        result = check_password_hash(self.password, raw_password)   # 相当于用相同的hash加密算法加密raw_password,检测与数据库中是否一致
        return result    

配置文件:config.py

import os    # 导入随机字符串用于加密session

SECRET_KEY = os.urandom(15)        # 产生随机15位字符串加密

2、错误登录信息渲染到前端界面

在后台登录的过程中,用户信息与数据库中数据不匹配的时候,产生的错误信息需要给用户看到错误的种类,此时就需要将错误信息渲染到后台登录的前端界面上,即cms_login.html页面。

views.py文件中将错误信息返回

# -*- encoding: utf-8 -*-
"""
@File    : views.py
@Time    : 2020/5/11 9:59
@Author  : chen

"""
# 蓝图文件:实现模块化应用,应用可以分解成一系列的蓝图   后端的类视图函数写在这个文件
from flask import Blueprint, render_template, views, session   # 定义类视图,显示模板文件
from flask import request, redirect, url_for          # 页面跳转redirect   request请求收集
# 导入form表单   .forms代表同级目录下的forms.py
from .forms import LoginForm

# 导入模型  .models代表同级目录下的models.py
from .models import CMS_User

cms_bp = Blueprint("cms", __name__, url_prefix='/cms/')     # URL前缀url_prefix


@cms_bp.route("/")                                          # 后台界面
def index():
    return "cms index:后端类视图文件"


# 定义类视图,显示模板文件
class LoginView(views.MethodView):
    def get(self, message=None):                                         # message=None时候不传输信息到cms_login.html页面
        return render_template("cms/cms_login.html", message=message)    # 针对post方法中同样要返回到cms_login.html页面进行代码简化
    
    # 用户登录操作验证
    def post(self):
        # 收集表单信息
        login_form = LoginForm(request.form)
        if login_form.validate():
            # 数据库验证
            email = login_form.email.data
            password = login_form.password.data
            remember = login_form.remember.data
            
            # 查询数据库中的用户信息
            user = CMS_User.query.filter_by(email=email).first()    # 邮箱唯一,用于查询验证用户
            if user and user.check_password(password):              # 验证用户和密码是否都正确
                session['user_id'] = user.id                        # 查询到用户数据时,保存session的id到浏览器
                if remember:                                        # 如果用户点击了remember选择,在浏览器中进行数据持久化
                    session.permanent = True                        # 数据持久化,默认31天,需要设置session_key在config.py中
            
                # 登录成功,跳转到后台首页
                return redirect(url_for('cms.index'))               # 在蓝图中必须加cms   跳转到index方法
            else:
                # return "邮箱或密码错误"                              # 登录出错,返回结果
                # return render_template("cms/cms_login.html", message="邮箱或密码错误")  # 登录出错,返回结果渲染到cms_login.html页面
                return self.get(message="邮箱或密码错误")             # 传参到get方法中,多加一个传输错误信息的参数到方法中
        else:
            print(login_form.errors)                                 # forms.py中的错误信息  字典类型数据
            print(login_form.errors.popitem())                       # forms.py中的错误信息  元祖类型数据
            # return "表单验证错误"                                   # 错误信息需要渲染到cms_login.html页面
            return self.get(message=login_form.errors.popitem()[1][0])  # 字典类型数据信息提取
        
    
# 添加登录路由
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login'))    # view_func 命名操作名字,"/login/"路由地址

其中要注意的是get()方法的修改和login_form.errors表单错误信息的提取。

渲染页面cms_login.html进行传参message


<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="description" content="">
    <meta name="author" content="">
<!--    <link rel="icon" href="../../favicon.ico">-->

    <title>CMS后台登录界面</title>

    <!-- Bootstrap core CSS -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

    <!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
    <!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
    <script src="../../assets/js/ie-emulation-modes-warning.js"></script>

    <!-- Custom styles for this template -->
<!--    <link href="signin.css" rel="stylesheet">-->

      <!--   这里引用自己的css模板文件 模板中引用静态资源文件使用url_for,路径filename='cms/css/signin.css')需要相对路径中的绝对路径-->
    <link href="{{ url_for('static', filename='cms/css/signin.css') }}" rel="stylesheet">
  </head>

  <body>

    <div class="container">

<!--    添加登录方法method="post"    -->
      <form class="form-signin" method="post">
        <h2 class="form-signin-heading">请登录</h2>
        <label for="inputEmail" class="sr-only">邮箱</label>
<!--    表单提交根据name="email"来接收后端数据      -->
        <input type="email" id="inputEmail" name="email" class="form-control" placeholder="邮箱地址" required autofocus>
        <label for="inputPassword" class="sr-only">密码</label>
<!--    表单提交根据name="password"来接收后端数据      -->
        <input type="password" id="inputPassword" name="password" class="form-control" placeholder="填写密码" required>
        <div class="checkbox">
          <label>
              <!--    表单提交根据name="remember"来接收后端数据      -->
            <input type="checkbox" value="remember-me" name="remember"> 记住我
          </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">立即登录</button>
      </form>

<!--   views.py中的表单验证输出的错误参数message进行渲染到前端界面   先判断message是否有信息,没有就不进行渲染  -->
        {% if message %}
            <!--      style="text-align:center" class="text-danger" 居中、红色字体样式      -->
            <p style="text-align:center" class="text-danger"> {{ message }}</p>
        {% endif %}

    </div> <!-- /container -->

    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
  </body>
</html>

这里需要注意的是:先判断message是否传有信息,没有就不进行渲染到界面中,运用到了if知识点。

3、钩子函数和装饰器

为了实现判断当前界面是否是登录界面,不是就将url重定向到登录界面这一功能,有两种方法实现:钩子函数、装饰器;分别进行介绍。

钩子函数

钩子函数中有函数方法before_first_request:处理第一次请求之前执行
用于实现判断当前界面是否是登录界面,不是就将url重定向到登录界面。

创建cms/hooks.py文件用于存放钩子函数

# -*- encoding: utf-8 -*-
"""
@File    : hooks.py
@Time    : 2020/5/13 9:36
@Author  : chen

"""
from flask import request, session, url_for,redirect
from .views import cms_bp


# 钩子函数 ,所有操作前执行该方法,判断当前界面是否是登录界面,不是就将url重定向到登录界面
@cms_bp.before_request
def before_request():
    print(request.path)                                         # 输出的是网页url的后缀,即/cms/login/
    if not request.path.endswith(url_for('cms.login')):    # 判断当前所在url是否是/cms/login/,不是代表不在后台登录界面
        user_id = session.get('user_id')                        # 登陆之后,获取登录时候记录的session中的user_id
        if not user_id:                                         # 若没有user_id,说明登录不成功
            return redirect(url_for('cms.login'))          # 重定向到后台登录界面

装饰器

装饰器也可以实现上面的功能,但是比较复杂难懂,后面创建的路由函数也都要再加上这个装饰器,比较麻烦,不建议使用。

创建cms/decorators.py文件用于存放装饰器

# -*- encoding: utf-8 -*-
"""
@File    : decorators.py
@Time    : 2020/5/12 22:38
@Author  : chen

"""
# 装饰器方法实现另一种判定后台用户当前界面是否是登录界面,不是就重定向到登录界面
from flask import session
from flask import redirect, url_for


def login_required(func):
    def inner(*args, **kwargs):              # 内层函数
        if 'user_id' in session:
            return func(*args, **kwargs)
        else:
            return redirect(url_for("cms.login"))
    return inner

需要注意的是,需要将上面的两种方法选择一个导入到cms/views.py文件中使用验证(推荐使用钩子函数,简单方便),这里注意导入的方式:

cms/views.py文件导入钩子函数

# -*- encoding: utf-8 -*-
"""
@File    : views.py
@Time    : 2020/5/11 9:59
@Author  : chen

"""
# 蓝图文件:实现模块化应用,应用可以分解成一系列的蓝图   后端的类视图函数写在这个文件
from flask import Blueprint, render_template, views, session   # 定义类视图,显示模板文件
from flask import request, redirect, url_for          # 页面跳转redirect   request请求收集
# 导入form表单   .forms代表同级目录下的forms.py
from .forms import LoginForm

# 导入模型  .models代表同级目录下的models.py
from .models import CMS_User

# 导入装饰器:判断当前界面是否是登录界面,不是就将url重定向到登录界面
from .decorators import login_required

cms_bp = Blueprint("cms", __name__, url_prefix='/cms/')     # URL前缀url_prefix

# 钩子函数是在cms_bp创建之后才创建的,顺序在cms_bp创建之后
from .hooks import before_request


@cms_bp.route("/")                                          # 后台界面
# @login_required             # 装饰器判定当前界面是否是登录界面,但是需要每个路由函数都要加该装饰器,比较麻烦,推荐使用钩子函数
def index():
    return "cms index:后端类视图文件"


# 定义类视图,显示模板文件   用户登录功能实现
class LoginView(views.MethodView):
    def get(self, message=None):                                         # message=None时候不传输信息到cms_login.html页面
        return render_template("cms/cms_login.html", message=message)    # 针对post方法中同样要返回到cms_login.html页面进行代码简化
    
    # 用户登录操作验证
    def post(self):
        # 收集表单信息
        login_form = LoginForm(request.form)
        if login_form.validate():
            # 数据库验证
            email = login_form.email.data
            password = login_form.password.data
            remember = login_form.remember.data
            
            # 查询数据库中的用户信息
            user = CMS_User.query.filter_by(email=email).first()    # 邮箱唯一,用于查询验证用户
            if user and user.check_password(password):              # 验证用户和密码是否都正确
                session['user_id'] = user.id                        # 查询到用户数据时,保存session的id到浏览器
                if remember:                                        # 如果用户点击了remember选择,在浏览器中进行数据持久化
                    session.permanent = True                        # 数据持久化,默认31天,需要设置session_key在config.py中
            
                # 登录成功,跳转到后台首页
                return redirect(url_for('cms.index'))               # 在蓝图中必须加cms   跳转到index方法
            else:
                # return "邮箱或密码错误"                              # 登录出错,返回结果
                # return render_template("cms/cms_login.html", message="邮箱或密码错误")  # 登录出错,返回结果渲染到cms_login.html页面
                return self.get(message="邮箱或密码错误")             # 传参到get方法中,多加一个传输错误信息的参数到方法中
        else:
            print(login_form.errors)                                 # forms.py中的错误信息  字典类型数据
            print(login_form.errors.popitem())                       # forms.py中的错误信息  元祖类型数据
            # return "表单验证错误"                                   # 错误信息需要渲染到cms_login.html页面
            return self.get(message=login_form.errors.popitem()[1][0])  # 字典类型数据信息提取
        
    
# 添加登录路由
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login'))    # view_func 命名操作名字,"/login/"路由地址

4、CSRF验证保护

CSRF验证保护是属于WEB安全中的知识点:需要在form表单进行post提交的时候,我们添加一个CSRF的token,用于确认访问者的身份确认,防止爬虫和黑客。

在这里插入图片描述
程序主文件引入CSRF保护:
项目主文件,启动入口bbs.py

# -*- encoding: utf-8 -*-
"""
@File    : bbs.py
@Time    : 2020/5/11 9:46
@Author  : chen

"""
# 项目主文件,启动入口

# 前台  front    管理前端界面的逻辑
# 后台  cms      管理后端的操作
# 公有的文件 common

from flask import Flask
import config      # 配置文件库
from exts import db    # 第三方库导入db
from apps.cms.views import cms_bp          # 导入后端蓝图文件
from apps.front.views import front_bp      # 导入前端蓝图文件
from flask_wtf import CSRFProtect          # CSRF表单保护验证

app = Flask(__name__)

CSRFProtect(app)                      # CSRF保护app

app.config.from_object(config)        # 添加配置

db.init_app(app)                      # 绑定app

app.register_blueprint(cms_bp)        # 后端蓝图文件注册
app.register_blueprint(front_bp)        # 前端蓝图文件注册


if __name__ == '__main__':
    app.run(debug=True, port=9999)

此时还需要在渲染的html文件中添加csrf_token信息用于验证:

后台显示界面cms_login.html文件

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="description" content="">
    <meta name="author" content="">
<!--    <link rel="icon" href="../../favicon.ico">-->

    <title>CMS后台登录界面</title>

    <!-- Bootstrap core CSS -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

      <!--   这里引用自己的css模板文件 模板中引用静态资源文件使用url_for,路径filename='cms/css/signin.css')需要相对路径中的绝对路径-->
    <link href="{{ url_for('static', filename='cms/css/signin.css') }}" rel="stylesheet">
  </head>

  <body>

    <div class="container">

<!--    添加登录方法method="post"    -->
      <form class="form-signin" method="post">
<!--    CSRF保护验证  type="hidden"页面隐藏这个信息,只用于验证保护    方法调用csrf_token()   -->
        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">

        <h2 class="form-signin-heading">请登录</h2>
        <label for="inputEmail" class="sr-only">邮箱</label>
<!--    表单提交根据name="email"来接收后端数据      -->
        <input type="email" id="inputEmail" name="email" class="form-control" placeholder="邮箱地址" required autofocus>
        <label for="inputPassword" class="sr-only">密码</label>
<!--    表单提交根据name="password"来接收后端数据      -->
        <input type="password" id="inputPassword" name="password" class="form-control" placeholder="填写密码" required>
        <div class="checkbox">
          <label>
              <!--    表单提交根据name="remember"来接收后端数据      -->
            <input type="checkbox" value="remember-me" name="remember"> 记住我
          </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">立即登录</button>
      </form>

<!--   views.py中的表单验证输出的错误参数message进行渲染到前端界面   先判断message是否有信息,没有就不进行渲染  -->
        {% if message %}
            <!--      style="text-align:center" class="text-danger" 居中、红色字体样式      -->
            <p style="text-align:center" class="text-danger"> {{ message }}</p>
        {% endif %}

    </div> <!-- /container -->

    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
  </body>
</html>

在这里插入图片描述

5、用户名渲染和注销功能

这里需要添加几个模板文件:
在这里插入图片描述
静态文件:static/cms/css/cms_base.css文件

/*
 * Base structure
 */

/* Move down content because we have a fixed navbar that is 50px tall */
body {
    padding-top: 50px;
    overflow: hidden;
}

/*
 * Global add-ons
 */

.sub-header {
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}

/*
 * Top navigation
 * Hide default border to remove 1px line.
 */
.navbar-fixed-top {
  border: 0;
}

/*
 * Sidebar
 */

/* Hide for mobile, show later */
.sidebar {
  display: none;
}
@media (min-width: 768px) {
  .sidebar {
    position: fixed;
    top: 51px;
    bottom: 0;
    left: 0;
    z-index: 1000;
    display: block;
    padding: 20px;
    overflow-x: hidden;
    overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
    background-color: #363a47;
    border-right: 1px solid #eee;
    margin-top: -1px;
  }
}

.nav-sidebar{
    padding: 5px 0;
    margin-left: -20px;
    margin-right: -20px;
}

.nav-sidebar > li{
    background: #494f60;
    border-bottom: 1px solid #363a47;
    border-top: 1px solid #666;
    line-height: 35px;
}

.nav-sidebar > li > a {
    background: #494f60;
    color: #9b9fb1;
    margin-left: 25px;
    display: block;
}

.nav-sidebar > li a span{
    float: right;
    width: 10px;
    height:10px;
    border-style: solid;
    border-color: #9b9fb1 #9b9fb1 transparent transparent;
    border-width: 1px;
    transform: rotate(45deg);
    position: relative;
    top: 10px;
    margin-right: 10px;
}

.nav-sidebar > li > a:hover{
    color: #fff;
    background: #494f60;
    text-decoration: none;
}

.nav-sidebar > li > .subnav{
    display: none;
}

.nav-sidebar > li.unfold{
    background: #494f60;
}

.nav-sidebar > li.unfold > .subnav{
    display: block;
}

.nav-sidebar > li.unfold > a{
    color: #db4055;
}

.nav-sidebar > li.unfold > a span{
    transform: rotate(135deg);
    top: 5px;
    border-color: #db4055 #db4055 transparent transparent;
}

.subnav{
    padding-left: 10px;
    padding-right: 10px;
    background: #363a47;
    overflow: hidden;
}

.subnav li{
    overflow: hidden;
    margin-top: 10px;
    line-height: 25px;
    height: 25px;
}

.subnav li.active{
    background: #db4055;
}

.subnav li a{
    /*display: block;*/
    color: #9b9fb1;
    padding-left: 30px;
    height:25px;
    line-height: 25px;
}

.subnav li a:hover{
    color: #fff;
}

.nav-group{
    margin-top: 10px;
}


.main {
  padding: 20px;
}
@media (min-width: 768px) {
  .main {
    padding-right: 40px;
    padding-left: 40px;
  }
}
.main .page-header {
  margin-top: 0;
}

/*
 * Placeholder dashboard ideas
 */

.placeholders {
  margin-bottom: 30px;
  text-align: center;
}
.placeholders h4 {
  margin-bottom: 0;
}
.placeholder {
  margin-bottom: 20px;
}
.placeholder img {
  display: inline-block;
  border-radius: 50%;
}

.main_content{
    margin-top: 20px;
}

.top-group{
    padding: 5px 10px;
    border-radius: 2px;
    background: #ecedf0;
    overflow: hidden;
}

静态文件:static/cms/css/sigin.css文件

body {
  padding-top: 40px;
  padding-bottom: 40px;
  background-color: #eee;
}

.form-signin {
  max-width: 330px;
  padding: 15px;
  margin: 0 auto;
}
.form-signin .form-signin-heading,
.form-signin .checkbox {
  margin-bottom: 10px;
}
.form-signin .checkbox {
  font-weight: normal;
}
.form-signin .form-control {
  position: relative;
  height: auto;
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
  padding: 10px;
  font-size: 16px;
}
.form-signin .form-control:focus {
  z-index: 2;
}
.form-signin input[type="email"] {
  margin-bottom: -1px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
  margin-bottom: 10px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

静态文件:static/cms/js/cms_base.js文件

/**
 * Created by Administrator on 2016/12/17.
 */

$(function () {
    $('.nav-sidebar>li>a').click(function (event) {
        var that = $(this);
        if(that.children('a').attr('href') == '#'){
            event.preventDefault();
        }
        if(that.parent().hasClass('unfold')){
            that.parent().removeClass('unfold');
        }else{
            that.parent().addClass('unfold').siblings().removeClass('unfold');
        }
        console.log('coming....');
    });

    $('.nav-sidebar a').mouseleave(function () {
        $(this).css('text-decoration','none');
    });
});


$(function () {
    var url = window.location.href;
    if(url.indexOf('profile') >= 0){
        var profileLi = $('.profile-li');
        profileLi.addClass('unfold').siblings().removeClass('unfold');
        profileLi.children('.subnav').children().eq(0).addClass('active').siblings().removeClass('active');
    } else if(url.indexOf('resetpwd') >= 0){
        var profileLi = $('.profile-li');
        profileLi.addClass('unfold').siblings().removeClass('unfold');
        profileLi.children('.subnav').children().eq(1).addClass('active').siblings().removeClass('active');
    } else if(url.indexOf('resetemail') >= 0){
        var profileLi = $('.profile-li');
        profileLi.addClass('unfold').siblings().removeClass('unfold');
        profileLi.children('.subnav').children().eq(2).addClass('active').siblings().removeClass('active');
    } else if(url.indexOf('posts') >= 0){
        var postManageLi = $('.post-manage');
        postManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('boards') >= 0){
        var boardManageLi = $('.board-manage');
        boardManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('permissions') >= 0){
        var permissionManageLi = $('.permission-manage');
        permissionManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('roles') >= 0){
        var roleManageLi = $('.role-manage');
        roleManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('users') >= 0){
        var userManageLi = $('.user-manage');
        userManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('cmsuser_manage') >= 0){
        var cmsuserManageLi = $('.cmsuser-manage');
        cmsuserManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('cmsrole_manage') >= 0){
        var cmsroleManageLi = $('.cmsrole-manage');
        cmsroleManageLi.addClass('unfold').siblings().removeClass('unfold');
    }else if(url.indexOf('comments') >= 0) {
        var commentsManageLi = $('.comments-manage');
        commentsManageLi.addClass('unfold').siblings().removeClass('unfold');
    }
});

静态文件:static/cms/js/resetpwd.js文件


$(function () {
    $("#submit").click(function (event) {
        // event.preventDefault
        // 是阻止按钮默认的提交表单的事件
        event.preventDefault();

        var oldpwdE = $("input[name=oldpwd]");
        var newpwdE = $("input[name=newpwd]");
        var newpwd2E = $("input[name=newpwd2]");

        var oldpwd = oldpwdE.val();
        var newpwd = newpwdE.val();
        var newpwd2 = newpwd2E.val();

        // 1. 要在模版的meta标签中渲染一个csrf-token
        // 2. 在ajax请求的头部中设置X-CSRFtoken
        var lgajax = {
            'get':function(args) {
                args['method'] = 'get';
                this.ajax(args);
            },
            'post':function(args) {
                args['method'] = 'post';
                this.ajax(args);
            },
            'ajax':function(args) {
                // 设置csrftoken
                this._ajaxSetup();
                $.ajax(args);
            },
            '_ajaxSetup': function() {
                $.ajaxSetup({
                    'beforeSend':function(xhr,settings) {
                        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
//                            var csrftoken = $('meta[name=csrf-token]').attr('content');
                            var csrftoken = $('input[name=csrf-token]').attr('value');
                            xhr.setRequestHeader("X-CSRFToken", csrftoken)
                        }
                    }
                });
            }
        };

        lgajax.post({
            'url': '/cms/resetpwd/',
            'data': {
                'oldpwd': oldpwd,
                'newpwd': newpwd,
                'newpwd2': newpwd2
            },
            'success': function (data) {
                console.log(data);
            },
            'fail': function (error) {
                console.log(error);
            }
        });
    });
});

模板文件:templates/cms/cms_index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>标题</title>
    <script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
    <link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<!--  关联本地的cms_base.css样式 后台管理界面CMS的样式 -->
    <link rel="stylesheet" href="{{ url_for('static', filename='cms/css/cms_base.css') }}">
<!--  关联本地的cms_base.js样式 后台管理界面CMS的样式 -->
    <script src="{{ url_for('static', filename='cms/js/cms_base.js') }}"></script>
</head>
<body>
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">论坛CMS管理系统</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
        <!--       从数据库中调用用户名,g对象全局调用g.cms_user      -->
            <li><a href="#">{{ g.cms_user }}<span>[超级管理员]</span></a></li>

        <!--  用户注销,关联到views.py中的@cms_bp.route("/logout/")路由,重定向到该路由      -->
            <li><a href="{{ url_for('cms.logout') }}">注销</a></li>
          </ul>
          <form class="navbar-form navbar-right">
            <input type="text" class="form-control" placeholder="查找...">
          </form>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
          <div class="col-sm-3 col-md-2 sidebar">
              <ul class="nav-sidebar">
                <li class="unfold"><a href="#">首页</a></li>
                <li class="profile-li">
                    <a href="#">个人中心<span></span></a>
                    <ul class="subnav">
                        <li><a href="#">个人信息</a></li>
                        <li><a href="#">修改密码</a></li>
                        <li><a href="#">修改邮箱</a></li>
                    </ul>
                </li>

                <li class="nav-group post-manage"><a href="#">帖子管理</a></li>
                <li class="comments-manage"><a href="#">评论管理</a></li>
                <li class="board-manage"><a href="#">板块管理</a></li>

                <li class="nav-group user-manage"><a href="#">用户管理</a></li>
                <li class="role-manage"><a href="#">组管理</a></li>

                <li class="nav-group cmsuser-manage"><a href="#">CMS用户管理</a></li>
                <li class="cmsrole-manage"><a href="#">CMS组管理</a></li>
            </ul>
          </div>
          <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <h1>BBS论坛</h1>
            <div class="main_content">
                欢迎来到BBS论坛
            </div>
          </div>
      </div>
    </div>
</body>
</html>

还需要对蓝图文件apps/cms/views.py进行修改:

  • 1、session中的用户信息需要传递到apps/cms/hooks.py中进行判断;
  • 2、对用户的注销操作进行函数编写,同时传递关联到templates/cms/cms_index.html中的注销属性;
# -*- encoding: utf-8 -*-
# -*- encoding: utf-8 -*-
"""
@File    : views.py
@Time    : 2020/5/11 9:59
@Author  : chen

"""
# 蓝图文件:实现模块化应用,应用可以分解成一系列的蓝图   后端的类视图函数写在这个文件
from flask import Blueprint, render_template, views, session   # 定义类视图,显示模板文件
from flask import request, redirect, url_for          # 页面跳转redirect   request请求收集
# 导入form表单   .forms代表同级目录下的forms.py
from .forms import LoginForm

# 导入模型  .models代表同级目录下的models.py
from .models import CMS_User

# 导入装饰器:判断当前界面是否是登录界面,不是就将url重定向到登录界面
from .decorators import login_required

cms_bp = Blueprint("cms", __name__, url_prefix='/cms/')     # URL前缀url_prefix

# 钩子函数是在cms_bp创建之后才创建的,顺序在cms_bp创建之后
from .hooks import before_request


@cms_bp.route("/")                                          # 后台界面
# @login_required             # 装饰器判定当前界面是否是登录界面,但是需要每个路由函数都要加该装饰器,比较麻烦,推荐使用钩子函数
def index():
    # return "cms index:后端类视图文件"
    return render_template('cms/cms_index.html')       # 登陆之后进入CMS后台管理界面,路径写全cms/cms_index.html


# 用户注销登录
@cms_bp.route("/logout/")                              # 需要关联到cms/cms_index.html中的注销属性
def logout():
    # session清除user_id
    del session['user_id']
    # 重定向到登录界面
    return redirect(url_for('cms.login'))             # 重定向(redirec)为把url变为重定向的url


# 定义个人中心的路由
@cms_bp.route("/profile/")
def profile():
    return render_template("cms/cms_profile.html")   # 模板渲染(render_template)则不会改变url,模板渲染是用模板来渲染请求的url


# 定义类视图,显示模板文件   用户登录功能实现
class LoginView(views.MethodView):
    def get(self, message=None):                                         # message=None时候不传输信息到cms_login.html页面
        return render_template("cms/cms_login.html", message=message)    # 针对post方法中同样要返回到cms_login.html页面进行代码简化
    
    # 用户登录操作验证
    def post(self):
        # 收集表单信息
        login_form = LoginForm(request.form)
        if login_form.validate():
            # 数据库验证
            email = login_form.email.data
            password = login_form.password.data
            remember = login_form.remember.data
            
            # 查询数据库中的用户信息
            user = CMS_User.query.filter_by(email=email).first()    # 邮箱唯一,用于查询验证用户
            if user and user.check_password(password):              # 验证用户和密码是否都正确
                session['user_id'] = user.id                        # 查询到用户数据时,保存session的id到浏览器
                # session['user_name'] = user.username                # 将数据库中的user.username保存到session中,在hooks.py中判断
                # session['user_email'] = user.email                  # 将数据库中的email保存到session中,方便html调用信息
                # session['user_join_time'] = user.join_time          # 将数据库中的join_time保存到session中,方便html调用信息
                
                if remember:                                        # 如果用户点击了remember选择,在浏览器中进行数据持久化
                    session.permanent = True                        # 数据持久化,默认31天,需要设置session_key在config.py中
            
                # 登录成功,跳转到后台首页
                return redirect(url_for('cms.index'))               # 在蓝图中必须加cms   跳转到index方法
            else:
                # return "邮箱或密码错误"                              # 登录出错,返回结果
                # return render_template("cms/cms_login.html", message="邮箱或密码错误")  # 登录出错,返回结果渲染到cms_login.html页面
                return self.get(message="邮箱或密码错误")             # 传参到get方法中,多加一个传输错误信息的参数到方法中
        else:
            print(login_form.errors)                                 # forms.py中的错误信息  字典类型数据
            print(login_form.errors.popitem())                       # forms.py中的错误信息  元祖类型数据
            # return "表单验证错误"                                   # 错误信息需要渲染到cms_login.html页面
            return self.get(message=login_form.errors.popitem()[1][0])  # 字典类型数据信息提取
        
    
# 添加登录路由
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login'))    # view_func 命名操作名字,"/login/"路由地址

session中的用户信息需要传递到apps/cms/hooks.py中进行判断:
修改apps/cms/hooks.py文件

# -*- encoding: utf-8 -*-
"""
@File    : hooks.py
@Time    : 2020/5/13 9:36
@Author  : chen

"""
from flask import request, session, url_for, redirect, g   # g对象全局变量gloabl,方便调用
from .views import cms_bp
from .models import CMS_User


# 钩子函数 ,所有操作前执行该方法,判断当前界面是否是登录界面,不是就将url重定向到登录界面
@cms_bp.before_request
def before_request():
    print(request.path)                                         # 输出的是网页url的后缀,即/cms/login/
    if not request.path.endswith(url_for('cms.login')):         # 判断当前所在url是否是/cms/login/,不是代表不在后台登录界面
        user_id = session.get('user_id')                        # 登陆之后,获取登录时候记录的session中的user_id
        if not user_id:                                         # 若没有user_id,说明登录不成功
            return redirect(url_for('cms.login'))               # 重定向到后台登录界面

    # 判断user_id是否登陆过,登录之后就返回用户名到CMS后台管理系统
    if 'user_id' in session:
        user_id = session.get('user_id')                        # 调用session中user_id
        user = CMS_User.query.get(user_id)                      # 通过user_id查询到用户对象,方便前端界面调用对象中的字段属性
        if user:
            g.cms_user = user                                   # 赋值给g对象,全局变量g.cms_user用于渲染到后台管理界面cms_index.html

# 上面的代码相对于下面的来说比较简单,下面的是将对象中的字段属性单独来调用并修改为全局变量,上面只是将完整的一个对象变成全局变量
'''
    # 判断user_id是否登陆过,登录之后就返回用户名到CMS后台管理系统
    if 'user_id' in session:                              # user_id在session中,说明cms用户已经登录了
        user_name = session.get('user_name')              # 从session中调用user_username
        user_email = session.get('user_email')            # 从session中调用user_email,用于设置为全局变量,渲染到cms_profile.html中
        user_join_time = session.get('user_join_time')    # 从session中调用user_join_time,用于设置为全局变量,渲染到cms_profile.html中

        if user_name:
            g.cms_user = user_name                        # 赋值给g对象,全局变量g.cms_user用于渲染到后台管理界面cms_index.html
            g.cms_email = user_email                      # 设置为全局变量,渲染到cms_profile.html中
            g.cms_join_time = user_join_time              # 设置为全局变量,渲染到cms_profile.html中
'''    

添加新的用户用于测试数据显示是否正常:
在这里插入图片描述
在这里插入图片描述

7、模板继承

创建新的模板文件templates/cms/cms_base.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}

    {% endblock %}</title>
    <script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
    <link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<!--  关联本地的cms_base.css样式 后台管理界面CMS的样式 -->
    <link rel="stylesheet" href="{{ url_for('static', filename='cms/css/cms_base.css') }}">
<!--  关联本地的cms_base.js样式 后台管理界面CMS的样式 -->
    <script src="{{ url_for('static', filename='cms/js/cms_base.js') }}"></script>

    {% block head %}

    {% endblock %}

</head>
<body>
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">论坛CMS管理系统</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
        <!--       从数据库中调用用户名,g对象全局调用g.cms_user对象  .username是该对象的一个字段属性      -->
            <li><a href="#">{{ g.cms_user.username }}<span>[超级管理员]</span></a></li>

        <!--  用户注销,关联到views.py中的@cms_bp.route("/logout/")路由,重定向到该路由      -->
            <li><a href="{{ url_for('cms.logout') }}">注销</a></li>
          </ul>
          <form class="navbar-form navbar-right">
            <input type="text" class="form-control" placeholder="查找...">
          </form>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
          <div class="col-sm-3 col-md-2 sidebar">
              <ul class="nav-sidebar">
                <li class="unfold"><a href="#">首页</a></li>
                <li class="profile-li">
                    <a href="#">个人中心<span></span></a>
                    <ul class="subnav">

                        <!--          url重定向到/cms/profile/下   这个路由在views.py中定义了       -->
                        <li><a href="{{ url_for('cms.profile') }}">个人信息</a></li>
                        <li><a href="#">修改密码</a></li>
                        <li><a href="#">修改邮箱</a></li>
                    </ul>
                </li>

                <li class="nav-group post-manage"><a href="#">帖子管理</a></li>
                <li class="comments-manage"><a href="#">评论管理</a></li>
                <li class="board-manage"><a href="#">板块管理</a></li>

                <li class="nav-group user-manage"><a href="#">用户管理</a></li>
                <li class="role-manage"><a href="#">组管理</a></li>

                <li class="nav-group cmsuser-manage"><a href="#">CMS用户管理</a></li>
                <li class="cmsrole-manage"><a href="#">CMS组管理</a></li>
            </ul>
          </div>
          <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <h1>{% block page_title %}

            {% endblock %}</h1>
            <div class="main_content">
                {% block content %}

                {% endblock %}
            </div>
          </div>
      </div>
    </div>
</body>
</html>

基础模板文件创建后,其他的cms_xxx.html文件就可以进行模板继承,不要大量的代码来渲染页面了

修改模板文件templates/cms/cms_index.html文件

<!--  继承模板文件cms/cms_base.html  简化代码 -->
{% extends 'cms/cms_base.html' %}

<!-- 页面标题 -->
{% block title %}
    CMS管理系统
{% endblock %}

<!--  标题  -->
{% block page_title %}
    欢迎来到CMS管理系统
{% endblock %}

<!-- 内容 -->
{% block content %}
    <!-- 引用相同的内容  -->
    {{ self.page_title() }}
{% endblock %}

模板文件templates/cms/cms_profile.html文件

<!--  继承模板文件cms/cms_base.html  简化代码 -->
{% extends 'cms/cms_base.html' %}

<!-- 页面标题 -->
{% block title %}
    个人信息
{% endblock %}

<!--  标题  -->
{% block page_title %}
    {{self.title()}}
{% endblock %}


{% block content %}
    <!--  将全局变量的对象在这个block模块中命名为user  -->
    {% set user = g.cms_user %}
    <table class="table table-bordered">
            <tr>
                <td>用户名:</td>
                <!--  调用全局变量对象的username字段属性  user替代g.cms_user       -->
                <td>{{ user.username }}</td>
            </tr>
            <tr>
                <td>邮箱:</td>
                <td>{{ user.email }}</td>
            </tr>
            <tr>
                <td>角色:</td>
                <td>暂未实现</td>
            </tr>
            <tr>
                <td>权限:</td>
                <td>暂未实现</td>
            </tr>
            <tr>
                <td>加入时间:</td>
                <td>{{ user.join_time }}</td>
            </tr>
    </table>
{% endblock %}

因为需要在templates/cms/cms_profile.html文件中调用到登录信息中的session的信息,所以需要针对apps/cms/views.py文件和apps/cms/hooks.py进行修改

视图文件apps/cms/views.py

# -*- encoding: utf-8 -*-
"""
@File    : views.py
@Time    : 2020/5/11 9:59
@Author  : chen

"""
# 蓝图文件:实现模块化应用,应用可以分解成一系列的蓝图   后端的类视图函数写在这个文件
from flask import Blueprint, render_template, views, session   # 定义类视图,显示模板文件
from flask import request, redirect, url_for          # 页面跳转redirect   request请求收集
# 导入form表单   .forms代表同级目录下的forms.py
from .forms import LoginForm

# 导入模型  .models代表同级目录下的models.py
from .models import CMS_User

# 导入装饰器:判断当前界面是否是登录界面,不是就将url重定向到登录界面
from .decorators import login_required

cms_bp = Blueprint("cms", __name__, url_prefix='/cms/')     # URL前缀url_prefix

# 钩子函数是在cms_bp创建之后才创建的,顺序在cms_bp创建之后
from .hooks import before_request


@cms_bp.route("/")                                          # 后台界面
# @login_required             # 装饰器判定当前界面是否是登录界面,但是需要每个路由函数都要加该装饰器,比较麻烦,推荐使用钩子函数
def index():
    # return "cms index:后端类视图文件"
    return render_template('cms/cms_index.html')       # 登陆之后进入CMS后台管理界面,路径写全cms/cms_index.html


# 用户注销登录
@cms_bp.route("/logout/")                              # 需要关联到cms/cms_index.html中的注销属性
def logout():
    # session清除user_id
    del session['user_id']
    # 重定向到登录界面
    return redirect(url_for('cms.login'))             # 重定向(redirec)为把url变为重定向的url


# 定义个人中心的路由
@cms_bp.route("/profile/")
def profile():
    return render_template("cms/cms_profile.html")   # 模板渲染(render_template)则不会改变url,模板渲染是用模板来渲染请求的url


# 定义类视图,显示模板文件   用户登录功能实现
class LoginView(views.MethodView):
    def get(self, message=None):                                         # message=None时候不传输信息到cms_login.html页面
        return render_template("cms/cms_login.html", message=message)    # 针对post方法中同样要返回到cms_login.html页面进行代码简化
    
    # 用户登录操作验证
    def post(self):
        # 收集表单信息
        login_form = LoginForm(request.form)
        if login_form.validate():
            # 数据库验证
            email = login_form.email.data
            password = login_form.password.data
            remember = login_form.remember.data
            
            # 查询数据库中的用户信息
            user = CMS_User.query.filter_by(email=email).first()    # 邮箱唯一,用于查询验证用户
            if user and user.check_password(password):              # 验证用户和密码是否都正确
                session['user_id'] = user.id                        # 查询到用户数据时,保存session的id到浏览器
                # session['user_name'] = user.username                # 将数据库中的user.username保存到session中,在hooks.py中判断
                # session['user_email'] = user.email                  # 将数据库中的email保存到session中,方便html调用信息
                # session['user_join_time'] = user.join_time          # 将数据库中的join_time保存到session中,方便html调用信息
                
                if remember:                                        # 如果用户点击了remember选择,在浏览器中进行数据持久化
                    session.permanent = True                        # 数据持久化,默认31天,需要设置session_key在config.py中
            
                # 登录成功,跳转到后台首页
                return redirect(url_for('cms.index'))               # 在蓝图中必须加cms   跳转到index方法
            else:
                # return "邮箱或密码错误"                              # 登录出错,返回结果
                # return render_template("cms/cms_login.html", message="邮箱或密码错误")  # 登录出错,返回结果渲染到cms_login.html页面
                return self.get(message="邮箱或密码错误")             # 传参到get方法中,多加一个传输错误信息的参数到方法中
        else:
            print(login_form.errors)                                 # forms.py中的错误信息  字典类型数据
            print(login_form.errors.popitem())                       # forms.py中的错误信息  元祖类型数据
            # return "表单验证错误"                                   # 错误信息需要渲染到cms_login.html页面
            return self.get(message=login_form.errors.popitem()[1][0])  # 字典类型数据信息提取
        
    
# 添加登录路由
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login'))    # view_func 命名操作名字,"/login/"路由地址

视图文件apps/cms/hooks.py

# -*- encoding: utf-8 -*-
"""
@File    : hooks.py
@Time    : 2020/5/13 9:36
@Author  : chen

"""
from flask import request, session, url_for, redirect, g   # g对象全局变量gloabl,方便调用
from .views import cms_bp
from .models import CMS_User


# 钩子函数 ,所有操作前执行该方法,判断当前界面是否是登录界面,不是就将url重定向到登录界面
@cms_bp.before_request
def before_request():
    print(request.path)                                         # 输出的是网页url的后缀,即/cms/login/
    if not request.path.endswith(url_for('cms.login')):         # 判断当前所在url是否是/cms/login/,不是代表不在后台登录界面
        user_id = session.get('user_id')                        # 登陆之后,获取登录时候记录的session中的user_id
        if not user_id:                                         # 若没有user_id,说明登录不成功
            return redirect(url_for('cms.login'))               # 重定向到后台登录界面

    # 判断user_id是否登陆过,登录之后就返回用户名到CMS后台管理系统
    if 'user_id' in session:
        user_id = session.get('user_id')                        # 调用session中user_id
        user = CMS_User.query.get(user_id)                      # 通过user_id查询到用户对象,方便前端界面调用对象中的字段属性
        if user:
            g.cms_user = user                                   # 赋值给g对象,全局变量g.cms_user用于渲染到后台管理界面cms_index.html

# 上面的代码相对于下面的来说比较简单,下面的是将对象中的字段属性单独来调用并修改为全局变量,上面只是将完整的一个对象变成全局变量
'''
    # 判断user_id是否登陆过,登录之后就返回用户名到CMS后台管理系统
    if 'user_id' in session:                              # user_id在session中,说明cms用户已经登录了
        user_name = session.get('user_name')              # 从session中调用user_username
        user_email = session.get('user_email')            # 从session中调用user_email,用于设置为全局变量,渲染到cms_profile.html中
        user_join_time = session.get('user_join_time')    # 从session中调用user_join_time,用于设置为全局变量,渲染到cms_profile.html中

        if user_name:
            g.cms_user = user_name                        # 赋值给g对象,全局变量g.cms_user用于渲染到后台管理界面cms_index.html
            g.cms_email = user_email                      # 设置为全局变量,渲染到cms_profile.html中
            g.cms_join_time = user_join_time              # 设置为全局变量,渲染到cms_profile.html中
'''   

实现效果如下:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章