Flask中提供了蓝图,专门用做Flask的模块化。对于蓝图,能够看官方介绍,这里翻译过来的:html
Flask使用蓝图的概念来制做应用程序组件和支持应用程序内部或跨应用程序的通用模式。蓝图能够大大简化大型应用程序的工做方式,并为Flask扩展提供了在应用程序上注册操做的中心手段。Blueprint对象的工做方式与Flask应用程序对象相似,但实际上它不是一个应用程序。相反,它是如何构造或扩展应用程序的蓝图。flask
总之,蓝图可使咱们的程序更加模块化,不一样功能的路由能够放在不一样的模块下,最后集中到启动类中cookie
蓝图,听起来就是一个很宏伟的东西session
在Flask中的蓝图 blueprint 也是很是宏伟的app
它的做用就是将 功能 与 主服务 分开怎么理解呢?ide
好比说,你有一个客户管理系统,最开始的时候,只有一个查看客户列表的功能,后来你又加入了一个添加客户的功能(add_user)模块, 而后又加入了一个删除客户的功能(del_user)模块,而后又加入了一个修改客户的功能(up_user)模块,在这个系统中,就能够将模块化
查看客户,修改客户,添加客户,删除客户的四个功能作成蓝图加入到客户管理系统中,本篇最后会作一个这样的例子,可是首先咱们要搞清楚什么是蓝图 blueprint函数
咱们先构建一个项目的目录结构如图所示:url
account.py的代码:spa
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对象中并无写任何的路由和视图函数
启动服务后访问 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不要出现重复,不然你就能够尝尝本身造的孽。
下面有一个情景:咱们在有的网页访问的时候咱们须要作一个简单的认证,只有登录的用户能够访问匿名用户不可以访问。
这里咱们的第一个方法读取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是否有恶意访问行为,从而进行拦截等操做
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写的位置决定了他是在全部的蓝图其效果仍是在单个蓝图里面其效果。
以下示例:
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,执行的顺序仍是先执行靠近视图函数的位置。
同时页面会返回前面要返回的信息。
启动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次请求。
不知道这个是否是我我的状况。
这个能够定义一些页面显示想要的画面,好比访问出现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)
访问一个不存在的页面会看到页面
没找到 这三个字