flask后续

Posted yang-china

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flask后续相关的知识,希望对你有一定的参考价值。

一、蓝图(BluePrint)

 蓝图是什么

Flask中提供了蓝图,专门用作Flask的模块化。对于蓝图,可以看官方介绍,这里翻译过来的:

Flask使用蓝图的概念来制作应用程序组件和支持应用程序内部或跨应用程序的通用模式。蓝图可以大大简化大型应用程序的工作方式,并为Flask扩展提供了在应用程序上注册操作的中心手段。Blueprint对象的工作方式与Flask应用程序对象类似,但实际上它不是一个应用程序。相反,它是如何构造或扩展应用程序的蓝图。

总之,蓝图可以使我们的程序更加模块化,不同功能的路由可以放在不同的模块下,最后集中到启动类中

 

蓝图,听起来就是一个很宏伟的东西

在Flask中的蓝图 blueprint 也是非常宏伟的

它的作用就是将 功能 与 主服务 分开怎么理解呢?

比如说,你有一个客户管理系统,最开始的时候,只有一个查看客户列表的功能,后来你又加入了一个添加客户的功能(add_user)模块, 然后又加入了一个删除客户的功能(del_user)模块,然后又加入了一个修改客户的功能(up_user)模块,在这个系统中,就可以将

查看客户,修改客户,添加客户,删除客户的四个功能做成蓝图加入到客户管理系统中,本篇最后会做一个这样的例子,但是首先我们要搞清楚什么是蓝图 blueprint

初识蓝图

我们先构建一个项目的目录结构如图所示:

技术分享图片

account.py的代码:

from flask import Blueprint  # 导入 Flask 中的蓝图 Blueprint 模块

ac = Blueprint(ac, __name__)  # 实例化一个蓝图(Blueprint)对象


@ac.route(/login/)   # 这里添加路由和视图函数的时候与在Flask对象中添加是一样的
def login():
    return Login

 

manager.py的代码为:

技术分享图片
from flask import Flask

# 导入此前写好的蓝图模块
from student_flask.account import ac

app = Flask(__name__)  # type:Flask

# 在Flask对象中注册蓝图模块中的蓝图对象 ac
app.register_blueprint(ac)

if __name__ == __main__:
    app.run(debug=True)
    # 现在Flask对象中并没有写任何的路由和视图函数
View Code

 

启动服务后访问 http://127.0.0.1:5000/login/ 

可以看到页面返回

Login

上面的示例,我们可以看出在flask中我们并没有添加路由,但是我们注册了有路由和视图函数的ac蓝图对象

在实例化蓝图的时候我们可以传递的一些参数

目录结构为

技术分享图片

 

上面我把蓝图放在一个目录下面,这个可以根据个人的喜好自己划分

user.py的代码为

from flask import Blueprint  # 导入 Flask 中的蓝图 Blueprint 模块
from flask import render_template

us = Blueprint("us",
               __name__,
               # 这里是相对路径,要加../
               template_folder="../us_templates",  
               # 每个蓝图都可以为自己独立出一套template模板文件夹
               # 如果不写则共享项目目录中的templates,并且他会先找和manager.py同级目录下,再找student_flask
               static_folder="../us_static"  # 静态文件目录也是可以独立出来的
               )  # 实例化一个蓝图(Blueprint)对象


@us.route("/index/")
def index():
    return render_template("index.html")

 

index.html的代码为

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>Hello ! I am peiqi</p>
    <img src="/us_static/xiaozhu.jpg">
</body>
</html>

 manager.py的代码为

from flask import Flask

# 导入此前写好的蓝图模块
from student_flask.views.account import ac
from student_flask.views.user import us

app = Flask(__name__)  # type:Flask

# 在Flask对象中注册蓝图模块中的蓝图对象 ac
app.register_blueprint(ac)
app.register_blueprint(us)

if __name__ == __main__:
    app.run(debug=True)
    # 现在Flask对象中并没有写任何的路由和视图函数

 

启动项目访问http://127.0.0.1:5000/index/得到

技术分享图片

这个是不是最新很流行哈哈

 

从这个例子中我们总结出:

Blueprint 其实可以理解为一个了没有run方法的 Flask 对象

只要Blueprint被 Flask 注册了,就一定会生效

注意了注意了注意了重要的事情说三遍

蓝图内部的视图函数及route不要出现重复,否则你就可以尝尝自己造的孽。

二、特殊装饰器

2.1 before_request

下面有一个情景:我们在有的网页访问的时候我们需要做一个简单的认证,只有登陆的用户可以访问匿名用户不能够访问。

方法一

这里我们的第一个方法读取cookies中的session中的信息看看该用户是否登陆没登录我们就给他跳到登录页面。代码如下

from flask import Blueprint, session, redirect, url_for, render_template

ac = Blueprint(ac, __name__)


@ac.route(/index)
def index():
    if not session.get(user):
        return redirect(url_for(login))
    return render_template(index.html)

 

上面写的只是蓝图的代码,其他的请参考前面的写法。

我们上面只有一个index页面如果我们有非常多的页面要我们验证上面的方法是不是非常繁琐,且代码重复。

方法二

这里我们就想到了装饰器,

from flask import Blueprint, session, redirect, url_for, render_template

import functools

ac = Blueprint(ac, __name__)


def auth(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        if not session.get(user):
            return redirect(url_for(login))
        ret = func(*args, **kwargs)
        return ret

    return inner


@ac.route(/index)
@auth
def index():
    return render_template(index.html)

 

上面就是我们使用装饰器达到的效果,在这里我们知道如果我们有成千上万个页面需要验证只有个别的不需要验证那每次前面都要加@auth是不是有点麻烦,且有时候还有可能忘记加了。

所以在这里我们还是感觉有点麻烦。所以使用下面的方法三也就是befor_request

方法三

使用before_request。

from flask import Blueprint, session, redirect, url_for, render_template, request

ac = Blueprint(ac, __name__)


@ac.before_request  # 这个就相当于Django中的中间件
def is_login():    # 判断是否登陆的函数
    if request.path == /login/:  # 设置的白名单
        return None

    if session.get(user):
        return None

    return redirect(/login)


@ac.route(/login/)
def login():
    return Login

注意:上面我们的这个装饰器是写在一个蓝图里面的所以这个装饰器也就只对这个蓝图起作用属于局部的,要想全局起作用就在注册蓝图的地方写这个特殊的装饰器。

还有上面用到的是蓝图所以在使用session的时候我们在上面没有设置配置里面的参数:SECRET_KEY = "qwerdf"。

完整目录如下

技术分享图片

全局的特殊装饰器卸载__init__.py里面。我们对flask的配置一般都写在settings里面。

@app.before_request 也是一个装饰器,他所装饰的函数,都会在请求进入视图函数之前执行

request.path 是来读取当前的url地址如果是 /login 就允许直接通过 return None 你可以理解成通过放行

校验session中是否有user 如果没有的话,证明没有登录,所以毫不留情的 redirect("/login") 跳转登录页面

还有一个要提的 @app.before_first_request 它与 @app.before_request 极为相似或者说是一模一样,只不过它只会被执行一次

@app.before_request修饰器在开发中用处非常大,比如判断某个ip是否有恶意访问行为,从而进行拦截等操作

 1.2 after_request

after_request和before_request对应,它是在响应(response)之前做出响应

from flask import Flask

app = Flask(__name__)

@app.after_request
def after1(response):
    print(after:1)
    return response

@app.route(/index/)
def index():
    print(index)
    return "Index"

if __name__ == __main__:
    app.run()

 

 

上面代码当我们访问http://127.0.0.1:5000/index/的时候我们可以在控制台看到

index
after:1

从结果可以看出我们是在执行index函数后执行after_request这个特殊的装饰器,也就是说当用户的请求得到响应的时候才会执行after_request.

这里注意了如果和上面一样使用了蓝图来开发,那么我们after_request写的位置决定了他是在所有的蓝图其效果还是在单个蓝图里面其效果。

1.3多个before_request和after_request。

如下示例:

from flask import Flask

app = Flask(__name__)


@app.before_request
def before1():
    print(before:1)


@app.before_request
def before2():
    print(before:2)


@app.after_request
def after1(response):
    print(after:1)
    return response


@app.after_request
def after2(response):
    print(after:2)
    return response


@app.route(/index/)
def index():
    print(index)
    return "Index"


if __name__ == __main__:
    app.run()

 

当我们访问http://127.0.0.1:5000/index/的时候在管理控制台我们可以看到

before:1
before:2
index
after:2
after:1

从上面的结果我们可以看出before_request谁写在前面,当我们访问某个视图的时候就先执行谁,而after_request相反,写在前面的后执行。

如果有一个before_request有返回值那么这个请求会怎么走?看一段代码

from flask import Flask

app = Flask(__name__)


@app.before_request
def before1():
    print(before:1)
    return "before:1"


@app.before_request
def before2():
    print(before:2)


@app.after_request
def after1(response):
    print("after:1")
    return response


@app.after_request
def after2(response):
    print("after:2")
    return response


@app.route(/index/)
def index():
    print(index)
    return "Index"


if __name__ == __main__:
    app.run(debug=True)

 

运行上面的代码,然后访问http://127.0.0.1:5000/

我们在控制台可以看到

before:1
127.0.0.1 - - [30/Jan/2019 14:53:48] "GET / HTTP/1.1" 200 -
after:2
after:1

当请求来的时候,在第一个before_request我们有返回值的时候,程序就会直接跳过视图函数,执行after_request,执行的顺序还是先执行靠近视图函数的位置。

同时页面会返回前面要返回的信息。

1.4  before_first_request

启动flask的时候处理第第一个请求的时候会被执行,接下来的请求不会被执行, 而before_request则表示每一个请求都会执行该特殊的装饰器。

而且当第一个请求执行的时候会先执行before_first_request在执行before_request,代码如下:

from flask import Flask

app = Flask(__name__)


@app.before_request
def xx1():
    print(before_request)


@app.before_first_request
def x1():
    print(before_first_request)


@app.route(/index/)
def index():
    print(index)
    return "Index"


@app.route(/order/)
def order():
    print(order)
    return "order"


if __name__ == __main__:
    app.run(debug=True)

 

我们先访问:http://127.0.0.1:5000/index/,在访问http://127.0.0.1:5000/order/

在管理控制台我们可以看到:

before_first_request
127.0.0.1 - - [30/Jan/2019 17:30:30] "GET /index/ HTTP/1.1" 200 -
before_request
index
before_request
127.0.0.1 - - [30/Jan/2019 17:30:37] "GET /order/ HTTP/1.1" 200 -
order

从上面可以看到当我们访问index的时候属于程序的第一次访问所以会执行before_first_request,当我们在访问order的时候,就没有执行before_first_request。

注意:当我们使用的访问地址为‘/index/‘,当我们访问http://127.0.0.1:5000/index,在我这里会自动重定向到http://127.0.0.1:5000/index/这个时候就相当于发送了2次请求。

不知道这个是不是我个人情况。

1.5 errorhandler

这个可以定义一些页面显示想要的画面,比如访问出现404的时候不想要他出现404而是出现自己想要页面。

from flask import Flask

app = Flask(__name__)


@app.errorhandler(404)
def not_found(arg):
    print(arg)
    return "没找到"


@app.route(/index/)
def index():
    print(index)
    return "Index"


if __name__ == __main__:
    app.run(debug=True)

 

访问一个不存在的页面会看到页面

没找到  这三个字

 

以上是关于flask后续的主要内容,如果未能解决你的问题,请参考以下文章

使用后续突变和缺失片段中继 commitUpdate 回调

Flask 编写http接口api及接口自动化测试

js常用代码片段

12_关于flask中的宏

Flask之模板之宏继承包含

Flask模板宏的概念和基本使用