Flask高级
关于Flask启动,和请求处理
#关于后端服务的启动,无非就是启动实现了WSGI协议的socket
#关于flask启动的无非就是下面两段代码
#加载配置,创建Flask对象
app = Flask(__name__)
#这个是启动werkzeug服务
app.run()
下面我们来分析上面两段代码
app.run()
run_simple(host, port, self, **options)找到起服务的核心代码
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
from .debughelpers import explain_ignored_app_run
explain_ignored_app_run()
return
if get_load_dotenv(load_dotenv):
cli.load_dotenv()
if "FLASK_ENV" in os.environ:
self.env = get_env()
self.debug = get_debug_flag()
elif "FLASK_DEBUG" in os.environ:
self.debug = get_debug_flag()
if debug is not None:
self.debug = bool(debug)
_host = "127.0.0.1"
_port = 5000
server_name = self.config.get("SERVER_NAME")
sn_host, sn_port = None, None
if server_name:
sn_host, _, sn_port = server_name.partition(":")
host = host or sn_host or _host
port = int(next((p for p in (port, sn_port) if p is not None), _port))
options.setdefault("use_reloader", self.debug)
options.setdefault("use_debugger", self.debug)
options.setdefault("threaded", True)
cli.show_server_banner(self.env, self.debug, self.name, False)
from werkzeug.serving import run_simple
try:
#############################################
#开启werkzeug服务
run_simple(host, port, self, **options)
finally:
self._got_first_request = False
请求-app.__call__()
上面我们已经启动了wsgi服务
run_simple(host, port, self, **options)
当来一个请求来的时候wsgi就会执行一次self()
当执行self()就相当于执行了app.__call__()
app.__call__()
def __call__(self, environ, start_response):
#来一次请求就执行一次这个函数
return self.wsgi_app(environ, start_response)
wsgi_app(environ, start_response)
#首先讲下函数的三个参数,self就是app,environ就行请求相关的数据,start_response是一个回调函数,是wsgi的用于返回一个响应行
def wsgi_app(self, environ, start_response):
#首先总览一下最核心的代码
#实例化一个ctx对象,里面封装了request和session等信息
ctx = self.request_context(environ)
error = None
try:
try:
#将ctx存到LOCAL对象的storage,存的格式为: storage={"执行id":{'stack':[ctx,]}}
#这个也就是flask的request的奇怪用法
ctx.push()
#这里主要实现的是请求扩展
#如before_first_request,信号,和请求拓展这些函数规则的定制
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
#返回响应信息
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
#删除ctx
ctx.auto_pop(error)
其他
蓝图-flask项目架构
蓝图的主要功能就是视图分离,不然所有视图写在一个文件会显得很杂乱
使用三步
-
创建蓝图
from flask import Blueprint #view user_bp = Blueprint('user',__name__)
-
利用蓝图创建路由关系
#view @bp.route('/login/') def login(): return "login"
-
注册蓝图
#app app.register_blueprint(bp)
注意
使用url_for,前面要加上蓝图名
url_for('zx.login')
实例
项目目录:
-templates
-static
-views
-user.py
-order.py
-app.py
views/user.py
from flask import Blueprint
# 1 创建蓝图
user_bp = Blueprint('user',__name__)
# 2 利用蓝图创建路由关系
@user_bp.route('/login/')
def login():
return "login"
@user_bp.route('/logout/')
def logout():
return "logout"
views/order.py
from flask import Blueprint
order_bp = Blueprint('order',__name__)
@order_bp.route('/add_order/')
def add_order():
return "add_order"
@order_bp.route('/modify_order/')
def modify_order():
return "modify_order"
app.py
from flask import Flask
from views.user import user_bp
from views.order import order_bp
app = Flask(__name__)
# 3 注册蓝图
app.register_blueprint(user_bp)
app.register_blueprint(order_bp)
if __name__ == '__main__':
app.run()
g对象
g对象使用周期是一次请求,先设置值,在取值
from flask import g
#设置值
g.name = "zx"
#取值
g.name
信号
安装
pip install blinker
内置信号
request_started = _signals.signal('request-started') # 请求到来前执行
request_finished = _signals.signal('request-finished') # 请求结束后执行
before_render_template = _signals.signal('before-render-template') # 模板渲染前执行
template_rendered = _signals.signal('template-rendered') # 模板渲染后执行
got_request_exception = _signals.signal('got-request-exception') # 请求执行出现异常时执行
request_tearing_down = _signals.signal('request-tearing-down') # 请求执行完毕后自动执行(无论成功与否)
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 应用上下文执行完毕后自动执行(无论成功与否)
appcontext_pushed = _signals.signal('appcontext-pushed') # 应用上下文push时执行
appcontext_popped = _signals.signal('appcontext-popped') # 应用上下文pop时执行
message_flashed = _signals.signal('message-flashed') # 调用flask在其中添加数据时,自动触发
使用信号
# 往信号中注册函数
def func(*args,**kwargs):
print('触发型号',args,kwargs)
#这个是内置信号
signals.request_started.connect(func)
一个源码中的内置信号
def full_dispatch_request(self):
"""Dispatches the request and on top of that performs request
pre and postprocessing as well as HTTP exception catching and
error handling.
.. versionadded:: 0.7
"""
self.try_trigger_before_first_request_functions()
try:
#这里看到没有
request_started.send(self)
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
return self.finalize_request(rv)
自定义信号
from flask import Flask, current_app, flash, render_template
from flask.signals import _signals
app = Flask(import_name=__name__)
# 自定义信号
xxxxx = _signals.signal('xxxxx')
def func(sender, *args, **kwargs):
print(sender)
# 自定义信号中注册函数
xxxxx.connect(func)
@app.route("/x")
def index():
# 触发信号
xxxxx.send('123123', k1='v1')
return 'Index'
if __name__ == '__main__':
app.run()
自定义session
我们知道Django的session是存在数据库的,而flask的默认是通过cookie实现的,那我们如果想要存在数据库怎么办呢?
安装
pip install flask-session
使用
from flask import Flask,session
from flask_session import RedisSessionInterface
import redis
app = Flask(__name__)
conn=redis.Redis(host='127.0.0.1',port=6379)
#use_signer是否对key签名,默认为false
#key_prefix为存储的k值的前缀
#permanent默认为True,浏览器关闭cookie失效
app.session_interface=RedisSessionInterface(conn,key_prefix='zx')
@app.route('/')
def hello_world():
session['name']='zx125'
print(session['name'])
return 'Hello World!'
if __name__ == '__main__':
app.run()
自定义命令
安装
pip install flask-script
使用
from flask_script import Manager
app = Flask(__name__)
manager=Manager(app)
...
if __name__ == '__main__':
manager.run()
#以后在执行,直接:python3 manage.py runserver
#python3 manage.py runserver --help
参考链接
https://www.cnblogs.com/xiaoyuanqujing/protected/articles/11715484.html