flask基础之app初始化(四)
前言
flask的核心对象是Flask,它定义了flask框架对于http请求的整个处理逻辑。随着服务器被启动,app被创建并初始化,那么具体的过程是这样的呢?
系列文章
一个最基本web应用的flask代码
from flask import Flask
import os
# 创建app对象
app = Flask(__name__,template_folder='static/html')
# 加载配置文件
app.config['SECRET_KEY'] = '123'
# 加载蓝图
app.register_blueprint(rest, url_prefix='')
# 加载请求钩子
@rest.before_request
def rest_test():
print('this is a test')
pass
# 定义api处理视图
@app.route('/test1')
def test():
return 'OK'
@定义错误处理逻辑
@app.errorhandler(400)
def handle_errer(errer):
print(errer)
return errer
if __name__ == '__main__':
app.run(host='127.0.0.1', port=80, debug=True)
如上所示,一个完整的web应用所拥有的最基本的东西就这些了,我们一步步分析。
第一步:创建Flask对象
创建一个Flask的app对象作为备用是一切的开端,看一下初始化干了什么?
class Flask(_PackageBoundObject):
request_class = Request # 指定请求对象
response_class = Response # 指定响应对象
jinja_environment = Environment # 指定前端模板语言环境
app_ctx_globals_class = _AppCtxGlobals # 设置app全局对象,本质是一个字典
request_globals_class = property(_get_request_globals_class, # 设置请求上下文全局对象,其等于app_ctx_globals_class
_set_request_globals_class)
config_class = Config # 设置参数配置对象
debug = ConfigAttribute('DEBUG') # 配置文件中如果DEBUG=True就启用debug模式
testing = ConfigAttribute('TESTING') # 配置文件中如果TESTING=True就启用TESTING模式
secret_key = ConfigAttribute('SECRET_KEY') # 配置文件中如果SECRET_KEY=‘xx’就启用了密匙,默认是不启用的
# 配置文件中如果SESSION_COOKIE_NAME=‘xx’就启用了在cookie中session信息的名字,默认是session
session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME')
# 配置文件中如果PERMANENT_SESSION_LIFETIM=‘xx’就启用了session信息的失效时间,默认是31天,即一个月
permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME',
get_converter=_make_timedelta)
# 设置发送文件功能最大的缓存超时时间,默认为12小时
send_file_max_age_default = ConfigAttribute('SEND_FILE_MAX_AGE_DEFAULT',
get_converter=_make_timedelta)
# 通过LOGGER_NAME指定日志对象的名称
logger_name = ConfigAttribute('LOGGER_NAME')
# 启用json格式的编解码
json_encoder = json.JSONEncoder
json_decoder = json.JSONDecoder
# 设置默认jinja模板环境
jinja_options = ImmutableDict(
extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
)
# 常用默认的配置集合
default_config = ImmutableDict({
'DEBUG': get_debug_flag(default=False), # 默认不开启DEBUG模式
'TESTING': False, # 默认不开启TESTING模式
'SECRET_KEY': None, # 默认没有密匙
'PERMANENT_SESSION_LIFETIME': timedelta(days=31), # 默认session失效时间一个月
'USE_X_SENDFILE': False, # 不启用X_SENDFILE功能
'LOGGER_NAME': None, # 不指定logger名字,使用的是__name__
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None, # 设置服务器的名字,默认None
'SESSION_COOKIE_NAME': 'session', # 设置cookie中的session名字
'MAX_CONTENT_LENGTH': None, # 限制提交请求的最大字节数
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), # 设置文件最大缓存时间
'PREFERRED_URL_SCHEME': 'http', # 默认的通讯协议
'JSONIFY_MIMETYPE': 'application/json', # 当json数据交互时,设置响应头的mimetype参数
})
url_rule_class = Rule # 指定路由对象管理路由
session_interface = SecureCookieSessionInterface() # 指定session会话对象
def __init__(self,
import_name, # 指定app的名字
static_path=None, # 会赋值给static_url_path参数,所以一般设置static_url_path而不是这个
static_url_path=None, # 设置静态文件路由的前缀,默认为“/static”,即static_folder的路径
static_folder='static', # 指定静态文件是哪个目录
template_folder='templates',# 模板文件的存放目录,默认值为"templates"
instance_path=None, # 设置配置文件的路径,在instance_relative_config=True情况下生效
instance_relative_config=False, # 设置为True表示配置文件相对于实例路径而不是根路径
root_path=None): # app所在的根路径,默认指的是创建app这个代码的文件的目录。
# 所有定义的视图函数存放字典,以视图函数的标识符为键,视图函数对象为字典;
self.view_functions = {}
# 所有自定义的错误处理方法的存放字典,以蓝图名字为键
self.error_handler_spec = {None: self._error_handlers}
# 所有的与url错误处理方法存放列表
self.url_build_error_handlers = []
# 所有的http请求处理前的请求钩子方法存放字典
self.before_request_funcs = {}
# 第一次请求处理前的请求钩子方法存放字典
self.before_first_request_funcs = []
# 所有的http请求处理后的请求钩子方法存放字典
self.after_request_funcs = {}
# 在处理即使存在异常的情况下的请求处理后的请求钩子方法存放字典
self.teardown_request_funcs = {}
# 应用上下文被弹出之前的处理函数存放点
self.teardown_appcontext_funcs = []
# url_value_preprocessor装饰器添加,URL路径预提取
self.url_value_preprocessors = {}
# url_defaults装饰器回调添加的,在生成url时设置规则参数默认值
self.url_default_functions = {}
self.blueprints = {} # 所有的蓝图的保存字典
self.extensions = {} # 所有的flask的扩展对象的存放字典
self.url_map = Map() # 所有的Rule对象保存的字典
# 添加访问静态文件的Rule对象
if self.has_static_folder:
self.add_url_rule(self.static_url_path + '/<path:filename>',
endpoint='static',
view_func=self.send_static_file)
初始化传入相关的参数后,会执行上述代码生成一个app对象。
第二步:加载配置文件
加载配置文件有多种方式,现在只说例子中的情况:
app.config['SECRET_KEY'] = '123'
app的config对象其实是Config实例,是一个dict类型的子类,也就是说app的配置是通过一个字典来保存的,新加载的配置如果键和原来默认的配置的键相同将更新,否则添加。
class Config(dict):
pass
详细的参数配置方式参考: flask之安装和使用入门
第三步:加载蓝图
app的register_blueprint方法就是用来加载蓝图的。
app.register_blueprint(rest, url_prefix='')
# 源码
def register_blueprint(self, blueprint, **options):
......
self.blueprints[blueprint.name] = blueprint
self._blueprint_order.append(blueprint)
blueprint.register(self, options, first_registration)
如上,在app的blueprints和_blueprint_order属性中添加蓝图对象,同时蓝图调用register方法初始化。
第四步:加载请求钩子
请求钩子常用的有五种,它们通过装饰器的方式添加到app相应的存储字典中。
before_first_request:在处理第一个请求前运行。
before_request:在每次请求前运行。
after_request:如果没有未处理的异常抛出,在每次请求后运行。
teardown_request:在每次请求后运行,即使有未处理的异常抛出。
teardown_appcontext:在每次请求结束后应用上下文被弹出时执行,即appcontext调用pop方法;
@app.before_request
def test():
pass
第五步:加载视图函数
app通过route装饰器加载视图函数,将标识符和视图函数作为键值对加入app的view_functions字典属性中。
@app.route('/test3', endpoint='mytest')
def test3():
return 'ok'
route装饰器调用了app.add_url_rule(rule, endpoint, f, **options)方法,主要源码步骤为:
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
...
rule = self.url_rule_class(rule, methods=methods, **options) # 创建一个Rule对象
。。。
self.url_map.add(rule) # 在app的url_map属性即Map对象中加入rule对象
。。。
self.view_functions[endpoint] = view_func # 在app的view_functions属性中加入标识符和视图函数的键值对
第六步:加载错误处理方法
app通过errorhandler装饰器加载对应的错误或状态码相应的处理方法。
@app.errorhandler(400)
def handle_errer(errer):
print(errer)
return errer
# 其主要源码
def _register_error_handler(self, key, code_or_exception, f):
# 可以传入状态码或我们自定义的异常
exc_class, code = self._get_exc_class_and_code(code_or_exception)
handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {})
handlers[exc_class] = f
总结
flask框架的核心对象有:
Flask,AppContext,Map, RequestContext,Request,Response,Rule,Blueprint,session,_AppCtxGlobals;Flask主要管理着AppContext,RequestContext,以及所有的请求的处理步骤;
AppContext为应用上下文对象,主要管理app对象的获取和请求的临时状态存储变量g;
RequestContext为请求上下文,主要管理Request对象和保存会话的session对象;
Request为请求对象,在发生请求是随着RequestContext被创建而创建,管理着请求数据和Rule对象;
Response为响应对象,在应用逻辑处理完毕后创建,管理着响应数据和响应方法;
Rule路由对象,管理着路由和视图处理函数的标识符的对应关系;
Map对象管理着所有的标识符和其视图函数对象的一一对应关系;
Blueprint对象,Flask对象的缩小版,主要是为了对大量的视图函数做分类管理;
session为保存会话信息的容器,可以看做一个字典;
_AppCtxGlobals即g变量,用来在每次请求中临时存储资源,它属于应用上下文的一个属性。
参考:
flask基础之app初始化(四)的更多相关文章
- flask基础之AppContext应用上下文和RequestContext请求上下文(六)
前言 应用上下文和请求上下文存在的目的,官方文档讲的很清楚,可参考: http://www.pythondoc.com/flask/appcontext.html 应用上下文对象在没有请求的时候是可以 ...
- flask基础之请求处理核心机制(五)
前言 总结一下flask框架的请求处理流程. 系列文章 flask基础之安装和使用入门(一) flask基础之jijia2模板使用基础(二) flask基础之jijia2模板语言进阶(三) flask ...
- 【视频】零基础学Android开发:蓝牙聊天室APP(四)
零基础学Android开发:蓝牙聊天室APP第四讲 4.1 ListView控件的使用 4.2 BaseAdapter具体解释 4.3 ListView分布与滚动事件 4.4 ListView事件监听 ...
- Flask 基础组件(四):模板
1.模板的使用 1.1 语法 1.1.1 流程控制 逻辑语法 Jinja2模板语言中的 for {% for foo in g %} {% endfor %} Jinja2模板语言中的 if {% ...
- Flask基础全套
Flask简介 Flask是主流PythonWeb三大框架之一,其特点是短小精悍以及功能强大从而获得众多Pythoner的追捧,相比于Django它更加简单更易上手,Flask拥有非常强大的三方库,提 ...
- 狗书无敌,天下第一(flask基础)
为什么选择使用flask? 和其他框架相比, Flask 之所以能脱颖而出,原因在于它让开发者做主,使其能对程序具有全面的创意控制. 在 Flask 中,你可以自主选择程序的组件,如果找不到合适的,还 ...
- flask基础三
一.路由和视图(基础二上补充) (1)有参装饰器 路由采用的是有参装饰器实现的 @app.route("/index",methods=["GET"," ...
- flask基础入门
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后 ...
- flask框架----flask基础
知识点回顾 1.flask依赖wsgi,实现wsgi的模块:wsgiref,werkzeug,uwsgi 2.实例化Flask对象,里面是有参数的 app = Flask(__name__,templ ...
随机推荐
- 2018 桂林ccpc现场赛 总结
Day 0 5个小时的火车,坐的昏昏欲睡.桂林站出来没有地铁,而是出租车排成长队依次上车,也算是某种意义上的地铁吧.到了酒店才发现学校那边又给我们换了,又拖着行李找新的酒店,途中路过一家餐馆,所有人都 ...
- Multiple Instance Learning
///////////////////////////////////////////推荐学习组////////////////////////////// http://www.robots.ox. ...
- [洛谷P4340][SHOI2016]随机序列
题目大意:有$n(n\leqslant10^5)$个数,每两个数之间可以加入$+-\times$三种符号,$q(q\leqslant10^5)$次询问,每次询问修改一个数后,所有表达式可能的值的和 题 ...
- 【BZOJ1034】泡泡堂(贪心)
[BZOJ1034]泡泡堂(贪心) 题面 BZOJ 洛谷 题解 很基础的贪心,然而我竟然没写对...身败名裂. 大概就是类似田忌赛马. 先拿看当前最大值是否能否解决对面最大值,否则检查能否用最小值来兑 ...
- 51nod 1295 XOR key | 可持久化Trie树
51nod 1295 XOR key 这也是很久以前就想做的一道板子题了--学了一点可持久化之后我终于会做这道题了! 给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X ...
- Jenkins(四)---Jenkins添加密钥对
一.添加密钥 1.添加git用户和git密码对 ,用于git客户端从gitlab上拉取代码到本地 /** lihaibo 文章内容都是根据自己工作情况实践得出. *版权声明:本博客欢迎转发,但请保留原 ...
- mysqldump导出多个数据库
mysqldump -uroot -p111111 -q -e -R -x --databases account game_s1 game_s2 ...... > D:\backup.sql ...
- Chapter 7(图)
1.Prim算法生成最小生成树 //Prim算法生成最小生成树 void MiniSpanTree_Prim(MGraph G) { int min,i,j,k; int adjvex[MAXVEX] ...
- shell实例浅谈之一产生随机数七种方法
一.问题 Shell下有时需要使用随机数,在此总结产生随机数的方法.计算机产生的的只是“伪随机数”,不会产生绝对的随机数(是一种理想随机数).伪随机数在大量重现时也并不一定保持唯一,但一个好的伪随机产 ...
- shell比较浮点数和整数
今天有一个朋友忽然问我在shell中,如何比较浮点数和整数,倒是把我问的一愣,在工作中确实没有遇到这个场景.我们也知道,在shell中数字的计算通常都会转换成整数,比如说1.1和1会被认为是一样的.这 ...