1. 配置文件
1.1 介绍
from flask import Flask
app = Flask( __name__)
print ( app. config)
flask中的配置文件是一个flask . config . Config对象 ( 继承dice字典 ) ,
默认配置为:
{
'DEBUG' : get_debug_flag( default= False ) ,
'TESTING' : False ,
'PROPAGATE_EXCEPTIONS' : None ,
'PRESERVE_CONTEXT_ON_EXCEPTION' : None ,
'SECRET_KEY' : None ,
'PERMANENT_SESSION_LIFETIME' : timedelta( days= 31 ) ,
'USE_X_SENDFILE' : False ,
'LOGGER_NAME' : None ,
'LOGGER_HANDLER_POLICY' : 'always' ,
'SERVER_NAME' : None ,
'APPLICATION_ROOT' : None ,
'SESSION_COOKIE_NAME' : 'session' ,
'SESSION_COOKIE_DOMAIN' : None ,
'SESSION_COOKIE_PATH' : None ,
'SESSION_COOKIE_HTTPONLY' : True ,
'SESSION_COOKIE_SECURE' : False ,
'SESSION_REFRESH_EACH_REQUEST' : True ,
'MAX_CONTENT_LENGTH' : None ,
'SEND_FILE_MAX_AGE_DEFAULT' : timedelta( hours= 12 ) ,
'TRAP_BAD_REQUEST_ERRORS' : False ,
'TRAP_HTTP_EXCEPTIONS' : False ,
'EXPLAIN_TEMPLATE_LOADING' : False ,
'PREFERRED_URL_SCHEME' : 'http' ,
'JSON_AS_ASCII' : True ,
'JSON_SORT_KEYS' : True ,
'JSONIFY_PRETTYPRINT_REGULAR' : True ,
'JSONIFY_MIMETYPE' : 'application/json' ,
'TEMPLATES_AUTO_RELOAD' : None ,
}
1.2 配置方式
列举几中常用的配置方式 .
1. app属性
直接给app对象赋值属性 , 因为只能配置两项 , debug和secret_key .
from flask import Flask
app = Flask( __name__)
app. debug = True
@app. route ( '/' )
def index ( ) :
return 'hello'
if __name__ == '__main__' :
app. run( )
2. 字典形式
以字典的形式,给flask配置文件做配置 .
from flask import Flask
app = Flask( __name__)
app. config[ "DEBUG" ] = on
@app. route ( '/' )
def index ( ) :
return 'hello'
if __name__ == '__main__' :
app. run( )
3. 配置文件
编写一个配置文件 , 在Flask项目中使用app . config . from_pyfile里传递配置文件的路径 .
* 1. 在项目目录下新建settings . py 配置文件 , ( 名称随意 , 符合命令规则即可 ) .
DEBUG = True
* 2. 在Flask项目中使用app . app . config . from_pyfile方法加载配置 .
from flask import Flask
app = Flask( __name__)
app. config. from_pyfile( 'settings.py' )
@app. route ( '/' )
def index ( ) :
return 'hello'
if __name__ == '__main__' :
app. run( )
4. 以类的形式
编写一个配置文件 , 以类的形式编写配置 , 一个文件可以用多个套配置,这样减少测试与更改 ( 推荐使用 ) ,
在Flask项目中使用app . config . from_object ( "python类或类的路径" ) 加载配置 .
* 1. 在项目目录下新建setobj . py 配置文件 , ( 名称随意 , 符合命令规则即可 ) .
class Config ( object ) :
DEBUG = False
TESTING = False
class TestingConfig ( Config) :
DEBUG = True
* 2. 在Flask项目中使用app . config . from_object ( ) 方法加载配置 .
from flask import Flask
app = Flask( __name__)
app. config. from_object( 'setobj.TestingConfig' )
@app. route ( '/' )
def index ( ) :
return 'hello'
if __name__ == '__main__' :
app. run( )
2. flask使用session
session [ '键' ] = 值
flask内置session通过SECRET_KEY的密钥进行加密后 , 当做cookie返回给浏览器 .
下次发送请求 , 会携带cookie过来 , 返解 , 在放到session中 .
session . get ( 'key' ) 将值取出 .
'SECRET_KEY' : None ,
'PERMANENT_SESSION_LIFETIME' : timedelta( days= 31 ) ,
'SESSION_COOKIE_NAME' : 'session' ,
'SESSION_COOKIE_DOMAIN' : None ,
'SESSION_COOKIE_PATH' : None ,
'SESSION_COOKIE_HTTPONLY' : True ,
'SESSION_COOKIE_SECURE' : False ,
'SESSION_REFRESH_EACH_REQUEST' : True ,
from flask import Flask, session
app = Flask( __name__)
app. secret_key = 'asdasdafa'
@app. route ( '/login' )
def login ( ) :
session[ 'user' ] = 'kid'
app. config[ 'SESSION_COOKIE_NAME' ] = 'session'
return '登入成功!'
@app. route ( '/index' )
def index ( ) :
user = session. get( 'user' )
print ( f'session的信息: { user} ' )
return 'index主页面'
if __name__ == '__main__' :
app. run( )
在浏览器中先访问 : http : / / 127.0 .0 .1 : 5000 /login 将用户信息保存到cookie中
再访问 : http : / / 127.0 .0 .1 : 5000 /login 将用户信息取出
3. CBV
Flask代码可以使用CBV方式写 , 视图类需要继承view或其子类 .
3.1 view类源码
def view ( ) :
print ( view. __name__)
view. __name__ = 'qwe'
print ( view. __name__)
view( )
class View :
methods: t. ClassVar[ t. Optional[ t. Collection[ str ] ] ] = None
provide_automatic_options: t. ClassVar[ t. Optional[ bool ] ] = None
decorators: t. ClassVar[ t. List[ t. Callable] ] = [ ]
init_every_request: t. ClassVar[ bool ] = True
def dispatch_request ( self) - > ft. ResponseReturnValue:
raise NotImplementedError( )
@classmethod
def as_view (
cls, name: str , * class_args: t. Any, ** class_kwargs: t. Any
) - > ft. RouteCallable:
if cls. init_every_request:
def view ( ** kwargs: t. Any) - > ft. ResponseReturnValue:
self = view. view_class(
* class_args, ** class_kwargs
)
return current_app. ensure_sync( self. dispatch_request) ( ** kwargs)
else :
self = cls( * class_args, ** class_kwargs)
def view ( ** kwargs: t. Any) - > ft. ResponseReturnValue:
return current_app. ensure_sync( self. dispatch_request) ( ** kwargs)
if cls. decorators:
view. __name__ = name
view. __module__ = cls. __module__
for decorator in cls. decorators:
view = decorator( view)
view. view_class = cls
view. __name__ = name
view. __doc__ = cls. __doc__
view. __module__ = cls. __module__
"""
将自己设置的methods给view对象的methods属性,
如果自己没有定义去父类view中查找None, (自己没设置为None)
默认仅支持GET.
在执行到添加路由 app.add_url_rule时
# 从路由中pop出设置的请求方法
methods = options.pop("methods", None)
# 如果路由装饰器中没有设置去视图类中获取methods属性的值,也没有设置的话 值为GET.
if methods is None:
methods = getattr(view_func, "methods", None) or ("GET",)
...
"""
view. methods = cls. methods
view. provide_automatic_options = cls. provide_automatic_options
return view
"""
如果没有view.__name__ = name, 那么没有设置endpoint参数的时候在执行_endpoint_from_view_func函数获取
被路由绑定的函数的名称, 都是view, 如果有多个应用, 就会会出现重名..
"""
3.2 继承view类
继承view类需要重写dispatch_request方法 , 从request中获取请求方式 , 并写对应的请求方法请求请求 .
如果需要限制请求方法 , 在类中设置methods属性的参数即可 .
如果需要使用装饰器则 , 在类中设置decorator属性的参数即可 .
from flask import Flask, request
from flask import views
app = Flask( __name__)
def login ( func) :
def inner ( * args, ** kwargs) :
print ( '执行装饰器' )
res = func( * args, ** kwargs)
return res
return inner
class IndexView ( views. View) :
methods = [ 'get' , 'post' ]
decorators = [ login]
def dispatch_request ( self) :
if request. method == 'GET' :
return self. get( )
def get ( self) :
print ( '执行get请求' )
return 'get'
app. add_url_rule( '/index' , view_func= IndexView. as_view( 'index' ) )
if __name__ == '__main__' :
app. run( )
在Postman中测试 , 输入地址 : http : / / 127.0 .0 .1 : 5000 /index ( 分别以不同的请求方式访问 )
访问成功 :
页面显示 get
终端显示 执行装饰器 ( 换行 ) 执行get请求
3.3 MethodView类源码
MethodView继承了View类 , 重写了dispatch_request方法 , methods属性也有默认值 .
class MethodView ( View) :
def __init_subclass__ ( cls, ** kwargs: t. Any) - > None :
super ( ) . __init_subclass__( ** kwargs)
if "methods" not in cls. __dict__:
methods = set ( )
for base in cls. __bases__:
if getattr ( base, "methods" , None ) :
methods. update( base. methods)
"""
http_method_funcs = frozenset(
["get", "post", "head", "options", "delete", "put", "trace", "patch"])
frozenset 不可变集合
"""
for key in http_method_funcs:
if hasattr ( cls, key) :
methods. add( key. upper( ) )
if methods:
cls. methods = methods
def dispatch_request ( self, ** kwargs: t. Any) - > ft. ResponseReturnValue:
meth = getattr ( self, request. method. lower( ) , None )
if meth is None and request. method == "HEAD" :
meth = getattr ( self, "get" , None )
assert meth is not None , f"Unimplemented method { request. method!r } "
return current_app. ensure_sync( meth) ( ** kwargs)
3.4 继承MethodView类
继承MethodView开发时可以省去重新dispatch_request方法 , 只写对应的请求方法即可 .
如果需要限制请求方法 , 在类中设置methods属性的参数即可 .
如果需要使用装饰器则 , 在类中设置decorator属性的参数即可 .
from flask import Flask
from flask import views
app = Flask( __name__)
def login ( func) :
def inner ( * args, ** kwargs) :
print ( '执行装饰器' )
res = func( * args, ** kwargs)
return res
return inner
class IndexView ( views. MethodView) :
decorators = [ login]
def get ( self) :
print ( '执行get请求' )
return 'get'
app. add_url_rule( '/index' , view_func= IndexView. as_view( 'index' ) )
if __name__ == '__main__' :
app. run( )
在Postman中测试 , 输入地址 : http : / / 127.0 .0 .1 : 5000 /index ( 分别以不同的请求方式访问 )
访问成功 :
页面显示 get
终端显示 执行装饰器 ( 换行 ) 执行get请求
4. 模板语法
django默认使用模板语法是DTL , 也可以改为jinja2 .
flask与DTL的使用方法几乎相识 , 区别 : jinja2支持函数加括号执行
参考学习 : https : / / blog . csdn . net / qq_46137324 / article / details / 123337020
模板语法的书写方法:
{ { 变量名 } } 变量相关
{ % % } 逻辑相关 for循环等
模板语法的取值格式 :
1. 句点符 . 键取值
2. 可以点索引
3. 两者混合使用
jinja2处理xss攻击 :
模板层 要渲染的字符串 | safe
后端 Markup ( '<input type="text">' )
* Markup等价django的mark_safe
pycharm设置jinja2模板代码提示 .
5. 请求响应
Flask的请求被封装到request函数中 .
request请求方法
. method 请求方法
. args 获取get请求提交的数据
. form 获取form表单提交的数据
. values get请求与post请求的数据总和
. query_string 获取get请求提交的数据 , 路由?后的参数 , 字符串格式 , 需要手动截数据
. cookie 获取cookie
. headers 请求头
. files 获取文件
. path 不带域名的 , 请求路径
. full_path 不带域名 , 带参数的请求路径
. script_root
. base_url 带域名带参数的请求路径
. url_root 域名
. host_url 域名
. host ip + 端口
5.1 请求方法
. method 请求方法
from flask import Flask, request
app = Flask( __name__)
@app. route ( '/' )
def index ( ) :
print ( request. method)
return 'index'
if __name__ == '__main__' :
app. run( )
浏览器中测试 , 输入 : http : / / 127.0 .0 .1 : 5000 /
5.2 获取get提交数据
. args 获取get请求提交的数据
结果是一个ImmutableMultiDict不可变字典
通过 ImmutableMultiDict . get ( key ) 获取值
如果有多个值通过 ImmutableMultiDict . getlist ( key ) , 得到一个列表 , 保存多个值 .
* 值只有一个使用 . getlist ( key ) 效果和get ( key ) 一样的 .
from flask import Flask, request
app = Flask( __name__)
@app. route ( '/' )
def index ( ) :
print ( request. args)
print ( request. args. get( 'name' ) )
print ( request. args. getlist( 'name' ) )
return 'index'
if __name__ == '__main__' :
app. run( )
浏览器中测试 , 输入 : http : / / 127.0 .0 .1 : 5000 /?name=kid&pwd= 123 & name = 123
* name有连个值
5.3 获取form表单数据
. form 获取form表单提交的数据
from flask import Flask, request
app = Flask( __name__)
@app. route ( '/' , methods= [ 'get' , 'post' ] )
def index ( ) :
print ( request. form)
return 'index'
if __name__ == '__main__' :
app. run( )
5.4 获取get/post请求数据总和
. values get请求与post请求的数据总和
from flask import Flask, request
app = Flask( __name__)
@app. route ( '/' , methods= [ 'post' ] )
def index ( ) :
print ( request. values)
return 'index'
if __name__ == '__main__' :
app. run( )
浏览器中测试 , 输入 : 127.0 .0 .1 : 5000 ?name = qq & age = 18 提交方式为post , 携带form-data的数据 .
如果提交给get请求 , get请求携带数据 , 请求提交就没有表单数据的数据了 .
get请求没有携带数据 , 提交表单数据可以 .
get请求携带数据 , 提交文件不影响 .
5.5 Flask使用cookie
* 1. 先通过make_response类生成 , response对象
* 2. response对象 . set_cookie ( 'key' , 'value' )
* 3. 将response对象返回 , 返回是会将cookie保存
* 4. request . cookies获取cookie , 值为不可变字典 .
from flask import Flask, request, make_response
app = Flask( __name__)
@app. route ( '/login' )
def login ( ) :
res = make_response( 'index' )
res. set_cookie( 'name' , 'kid' )
return res
@app. route ( '/index' )
def index ( ) :
print ( request. cookies)
return 'index'
if __name__ == '__main__' :
app. run( )
浏览器中测试 :
先输入 : 127.0 .0 .1 : 5000 /login 保存cookie到客户端
再输入 : 127.0 .0 .1 : 5000 /index 获取请求携带cookie
5.6 获取请求头信息
from flask import Flask, request
app = Flask( __name__)
@app. route ( '/' )
def index ( ) :
print ( request. headers)
"""
Cookie: 123
---上面是自己添加到请求头的信息, 下面是默认获取的信息----
User-Agent: PostmanRuntime/7.29.0
Accept: */*
Postman-Token: 8d2662e4-7ecd-4038-9c1d-22d8df6cf74d
Host: 127.0.0.1:5000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
"""
return 'index'
if __name__ == '__main__' :
app. run( )
5.7 获取文件信息
通过表单提交文件 , 后端读取文件 , 保存到本地 .
from flask import Flask, request
app = Flask( __name__)
@app. route ( '/' )
def index ( ) :
print ( request. files)
img_obj = request. files. get( 'file' )
with open ( img_obj. filename, mode= 'wb' ) as wf:
for i in img_obj:
wf. write( i)
return 'index'
if __name__ == '__main__' :
app. run( )
5.8 路径相关
. path 不带域名的 , 请求路径
@ app . route ( '/' ) http : / / 127.0 .0 .1 : 5000 得到 : /
. full_path 不带域名 , 带参数的请求路径
@ app . route ( '/' ) http : / / 127.0 .0 .1 : 5000 /?name=kid 得到 : / ?name = kid
. base_url 带域名带请求路径 , 不带参数
@ app . route ( '/index' ) 127.0 .0 .1 : 5000 /index?name=kid 得到 : http : / / 127.0 .0 .1 : 5000 /index
. url_root 域名 得到 : http : / / 127.0 .0 .1 : 5000 /
. host_url 域名 得到 : http : / / 127.0 .0 .1 : 5000 /
. host ip : 端口 得到 : 127.0 .0 .1 : 5000
6. 响应对象
返回字符串信息 : return '字符串' 或 字符串格式html
返回html模板 : return render_template ( 'html文件' , * * loacls ( ) )
重定向 : return redirect ( '地址' )
返回json格式数据 : return jsonify ( { 'key' = 'value' } )
6.1 返回html页面
* 1. 在项目目录下新建templates目录
* 2. 在templates目录下新建index . html文件
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> Title</ title>
</ head>
< body>
{{ name }}
{{ age }}
</ body>
</ html>
* 3. 新建main . py 文件
from flask import Flask, render_template
app = Flask( __name__)
@app. route ( '/' )
def index ( ) :
name = 'kid'
age = 18
print ( locals ( ) )
return render_template( 'index.html' , ** locals ( ) )
if __name__ == '__main__' :
app. run( )
* 4. 浏览器中测试 : 127.0 .0 .1 : 5000
6.2 返回json格式数据
rom flask import Flask, jsonify
app = Flask( __name__)
@app. route ( '/' )
def index ( ) :
"""
{
"name": "kid"
}
"""
"""
{
"age": 18
}
"""
return jsonify( { 'age' : 18 } )
if __name__ == '__main__' :
app. run( )
6.3 返回response对象
见 5.5 小节返回response对象 , 携带cookie .
7. session
7.1 session的使用
from flask import Flask, session
app = Flask( __name__)
app. secret_key = 'asd'
"""
session 是通过 session+盐+secret_key 生成的
需要设置 key 否则会报错 ↓
RuntimeError: The session is unavailable because no secret key was set.
Set the secret_key on the application to something unique and secret.
"""
@app. route ( '/set_session' )
def set_session ( ) :
session[ 'name' ] = 'kid'
return 'set_session'
@app. route ( '/get_session' )
def get_session ( ) :
name = session. get( 'name' )
print ( name)
return 'get_session'
@app. route ( '/del_session' )
def delete ( ) :
session. pop( 'name' )
return 'delete_session'
if __name__ == '__main__' :
app. run( )
测试 :
1. 先访问 set_session 保存session session [ 'name' ] = 'kid'
2. 再访问 get_session 获取session session . get ( 'name' ) 值为kid
3. 再访问 del_session 删除session session . pop ( 'name' )
4. 再访问 get_session 获取session session . get ( 'name' ) 值为None
7.2 源码解析
from flask import Flask, session
app = Flask( __name__)
app. secret_key = 'asd'
app. session_interface
session_interface: SessionInterface = SecureCookieSessionInterface( )
class SecureCookieSessionInterface ( SessionInterface) :
salt = "cookie-session"
digest_method = staticmethod ( hashlib. sha1)
key_derivation = "hmac"
serializer = session_json_serializer
session_class = SecureCookieSession
def get_signing_serializer (
self, app: "Flask"
) - > t. Optional[ URLSafeTimedSerializer] :
if not app. secret_key:
return None
signer_kwargs = dict (
key_derivation= self. key_derivation, digest_method= self. digest_method
)
return URLSafeTimedSerializer(
app. secret_key,
salt= self. salt,
serializer= self. serializer,
signer_kwargs= signer_kwargs,
)
def open_session (
self, app: "Flask" , request: "Request"
) - > t. Optional[ SecureCookieSession] :
s = self. get_signing_serializer( app)
if s is None :
return None
val = request. cookies. get( self. get_cookie_name( app) )
if not val:
return self. session_class( )
max_age = int ( app. permanent_session_lifetime. total_seconds( ) )
try :
data = s. loads( val, max_age= max_age)
return self. session_class( data)
except BadSignature:
return self. session_class( )
def save_session (
self, app: "Flask" , session: SessionMixin, response: "Response"
) - > None :
name = self. get_cookie_name( app)
domain = self. get_cookie_domain( app)
path = self. get_cookie_path( app)
secure = self. get_cookie_secure( app)
samesite = self. get_cookie_samesite( app)
httponly = self. get_cookie_httponly( app)
"""
session 为空 modified的值为True时触发, 将cookie的信息删除
modified是一个标准位, 为session设置值之后 modified的值为True
删除session session.pop() session为空时 modified的值为True 清除掉cookie
"""
if not session:
if session. modified:
response. delete_cookie(
name,
domain= domain,
path= path,
secure= secure,
samesite= samesite,
httponly= httponly,
)
return
if session. accessed:
response. vary. add( "Cookie" )
if not self. should_set_cookie( app, session) :
return
expires = self. get_expiration_time( app, session)
val = self. get_signing_serializer( app) . dumps( dict ( session) )
response. set_cookie(
name,
val,
expires= expires,
httponly= httponly,
domain= domain,
path= path,
secure= secure,
samesite= samesite,
)
如果自定义session的存放方式 , 继承SessionInterface重写几个方法即可 .
在为app . session_interface属性设置为自定义类的对象即可 .
保存session的时候会调用save_session ,
将session加密得到签名 ( 不可变字典- > 字符串 ) , 将签名存放到cookie中 ( session : 签名字符串 ) .
访问页面的时候从cookie中取出加签名字符串 , 反解得到不可变字典 .
8. 闪现
Flask的闪现功能将数据存入session中 , 可以在不同的视图函数中多次存储 , 获取一次之后就会删除session中的数据 .
8.1 基本存储
存储 :
falsh [ 'value' ]
取所有值 :
get_flashed_messages ( )
from flask import Flask, flash, get_flashed_messages
app = Flask( __name__)
app. secret_key = 'asd'
@app. route ( '/set_flash1' )
def set_flash1 ( ) :
flash( 'hello' )
return 'set_session'
@app. route ( '/set_flash2' )
def set_flash2 ( ) :
flash( 'world!' )
return 'set_session'
@app. route ( '/get_flash1' )
def get_flash1 ( ) :
print ( get_flashed_messages( ) )
return 'get_session'
@app. route ( '/get_flash2' )
def get_flash2 ( ) :
print ( get_flashed_messages( ) )
return 'get_session'
if __name__ == '__main__' :
app. run( )
测试 :
先访问 set_flash1 flash ( 'hello' ) 将hello保存到session中 .
再访问 set_flash1 flash ( 'world!' ) 将world ! 保存到session中 .
再访问 get_flash1 get_flashed_messages ( ) 获取保存到session中的信息
再访问 get_flash2 get_flashed_messages ( ) 已经被获取过后信息被清除了 , 得到一个空列表 .
8.2 分成存储
分类存储 :
falsh [ 'value' , category = '分类名' ]
按分类取值 :
get_flashed_messages ( category_filter = '分类名' )
get_flashed_messages ( category_filter = [ '分类名' ] )
from flask import Flask, flash, get_flashed_messages
app = Flask( __name__)
app. secret_key = 'asd'
@app. route ( '/set_flash1' )
def set_flash1 ( ) :
flash( 'hello' , category= 't1' )
return 'set_session'
@app. route ( '/set_flash2' )
def set_flash2 ( ) :
flash( 'world!' , category= 't2' )
return 'set_session'
@app. route ( '/get_flash1' )
def get_flash1 ( ) :
print ( get_flashed_messages( category_filter= 't1' ) )
return 'get_session'
@app. route ( '/get_flash2' )
def get_flash2 ( ) :
print ( get_flashed_messages( category_filter= 't2' ) )
return 'get_session'
if __name__ == '__main__' :
app. run( )
测试 :
先访问 set_flash1 flash ( 'hello' ) 将hello保存到session中 , 分类为t1 .
再访问 set_flash1 flash ( 'world!' ) 将world ! 保存到session中 , 分类为t2 .
再访问 get_flash1 get_flashed_messages ( category_filter = 't1' ) 获取保存到session中的t1分类的信息 .
再访问 get_flash2 get_flashed_messages ( category_filter = 't2' ) 已经被获取过后所有信息被清除了 , 得到一个空列表 .
9. 请求拓展
请求拓展类似Django的中间件 , 请求前 , 请求后 , 执行什么操作 .
基于装饰器实现 , 绑定一个函数执行一些操作 .
9.1 请求来时触发
请求来时就会触发 , 类似django的process_request .
有返回值 , 一般为None , 如果直接返回response对象 , 直接返回 . 不往后执行 .
@app. beform_requesr
def process_request ( * args, ** kwargs)
. . .
9.2 请求走时触发
请求走时就会触发 , 类似django的process_response .
@app. after_request
def process_response ( * args, ** kwargs)
. . .
9.3 请求拓展实例
1. 实例1
请求的执行顺序 , 先执行before_request , 再执行视图函数 , 最后执行after_request .
from flask import Flask, session, request, redirect
app = Flask( __name__)
app. debug = True
app. secret_key = 'asd'
@app. before_request
def process_request ( * args, ** kwargs) :
print ( * args, ** kwargs)
if request. path == '/login' :
return None
if not session. get( 'name' ) :
return redirect( '/login' )
@app. after_request
def process_response ( response) :
if request. path == '/index' :
print ( response)
if session. get( 'name' ) :
session. pop( 'name' )
return response
@app. route ( '/login' )
def login ( ) :
session[ 'name' ] = 'kid'
return '登入成功!'
@app. route ( '/index' )
def index ( ) :
return 'index主页面'
if __name__ == '__main__' :
app. run( )
测试 :
先访问 index , ( 这个时候session中没有值 . )
第一步 :
访问来时执行process_request函数 , 对访问地址进行判断 , 如果是 '/login' 直接放行 ,
不是则从请求中获取session , session有值则放行 , 否则重定向到登入页面 . -- > session没有值 , 执行重定向 .
第二步 :
重定向时 , 先经过process_response含 , 对访问地址进行判断 , 如果是 '/index' , 判断session中是否有值 , 如果有则清除 .
第三步 :
浏览器向服务端重新发送请求 , 访问到 '/login' , 先执行process_request函数 , -- > 放行
第四步 :
执行login函数 , 保存session . 返回 '登入成功' , 再经过process_response , -- > 放行
再次访问 index , ( 这个时候session中有值 . )
第一步 :
访问来时执行process_request函数 , session有值 , -- > 放行
第二步 :
执行index函数 , 返回 'index主页面' 主页面 , 再进过process_response , session中有值 , 则将session值删除
2. 实例2
在before_request中直接返回response对象 , 会执行所有响应不会执行视图函数 .
from flask import Flask, make_response
app = Flask( __name__)
@app. before_request
def ip_filter ( ) :
res = make_response( '你的访问被限制!' )
return res
@app. after_request
def after1 ( response) :
print ( '请求走了1!' )
return response
@app. after_request
def after2 ( response) :
print ( '请求走了2!' )
return response
@app. route ( '/' )
def index ( ) :
return 'index'
if __name__ == '__main__' :
app. run( )
9.4 执行顺序
before_request 从上往下执行 ,
after_request 重下往上执行 .
from flask import Flask
app = Flask( __name__)
app. debug = True
@app. before_request
def process_request1 ( * args, ** kwargs) :
print ( 1 )
@app. before_request
def process_request2 ( * args, ** kwargs) :
print ( 2 )
@app. after_request
def process_response1 ( response) :
print ( 5 )
return response
@app. after_request
def process_response2 ( response) :
print ( 4 )
return response
@app. route ( '/' )
def index ( ) :
print ( 3 )
return '登入成功!'
if __name__ == '__main__' :
app. run( )
终端显示 :
1
2
3
4
5
9.5 第一次请求触发
第一次请求时 , 跟浏览器无关 .
这个是django中没有的 . 仅再项目启动时 , 接收到第一次请求时触发 , 与浏览器和用户无关 .
如果写多个 , 会将函数名存到一个列表中依次执行 .
使用场景 : 项目初始化 .
@app. beffore_first_request
def first ( ) :
pass
9.6 所有请求触发
teardown_request注册一个在每个请求结束时要调用的函数 , 无论该函数成功还是引发异常 .
使用场景 : 记录错误日志 , 清理请求作用域对象 ( 如数据库会话 / 事务 )
from flask import Flask
app = Flask( __name__)
app. debug = True
@app. after_request
def process_request ( response) :
print ( '执行了process_request' )
return response
@app. teardown_request
def teardown ( e) :
print ( '执行了teardown_request' )
@app. route ( '/' )
def index ( ) :
print ( 'index' )
return 'index主页面'
@app. route ( '/order' )
def order ( ) :
print ( 'order1' )
a
print ( 'order2' )
return 'order页面'
if __name__ == '__main__' :
app. run( )
测试 :
访问根目录 , 先执行 index函数 , 再执行process_request函数 , 最后执行teardown_request函数 .
再次访问 '/order' , 先执行index函数 , 打印 'order1' , 报错 . . . , 报错前执行teardown_request函数 .
9.7 异常时触发
出现异常的时候触发 , 可以根据状态码触发对应的处理函数 .
@app. errorhandler ( 400 )
def error_400 ( ) :
pass
写一个函数 , 处理所有的 404 响应状态码 .
* 1. templates 下新建error . html页面
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> Title</ title>
</ head>
< body>
{{ error_msg }}
</ body>
</ html>
* 2. 404 状态码处理函数
from flask import Flask, render_template
app = Flask( __name__)
app. debug = False
@app. errorhandler ( 404 )
def error_404 ( e) :
print ( e)
return render_template( 'error.html' , error_msg= '404错误页面' )
@app. errorhandler ( 500 )
def error_500 ( e) :
print ( e)
return render_template( 'error.html' , error_msg= '500错误页面' )
@app. route ( '/' )
def index ( ) :
a
return 'index'
if __name__ == '__main__' :
app. run( )
* 3. 测试 :
访问所有不存在的路由 , 会返回 404 , 返回时 , 触发errorhandler ( 404 ) .
访问根路径 , 会返回 500 , 返回时 , 触发errorhandler ( 500 ) .
9.8 全局标签
@ app . template_global ( ) 全局标签再后端定义 , 前端模板页面任何位置中可以调用 .
from flask import Flask, render_template
app = Flask( __name__)
@app. template_global ( )
def num_add ( x, y) :
return x + y
@app. route ( '/' )
def index ( ) :
return render_template( 'index.html' )
if __name__ == '__main__' :
app. run( )
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> Title</ title>
</ head>
< body>
{{ num_add(1, 2) }}
</ body>
</ html>
9.9 全局过滤器
@ app . template_filter 全局标签再后端定义 , 前端模板页面任何位置中可以调用 .
* 注意传递参数的方式 .
from flask import Flask, render_template
app = Flask( __name__)
@app. template_filter ( )
def num_add ( x, y, z) :
return x + y + z
@app. route ( '/' )
def index ( ) :
return render_template( 'index.html' )
if __name__ == '__main__' :
app. run( )
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> Title</ title>
</ head>
< body>
{{ 1|num_add(2, 3) }}
</ body>
</ html>