常说 Flask 是「Werkzeug + Jinja2」,具体是哪些类、哪些功能来自它们?只用 Werkzeug 能做到什么?Flask 又多加了什么?这篇用继承链、依赖列表和一个纯 Werkzeug 应用来回答。
Requires-Dist(不含可选的 extra):
blinker>=1.9.0
click>=8.1.3
importlib-metadata>=3.6.0; python_version < '3.10'
itsdangerous>=2.2.0
jinja2>=3.1.2
markupsafe>=2.1.1
werkzeug>=3.1.0
本机实际安装的版本: {'flask': '3.1.3', 'werkzeug': '3.1.9', 'jinja2': '3.1.6', 'itsdangerous': '2.2.0', 'click': '8.5.0', 'markupsafe': '3.0.3', 'blinker': '1.9.0'} Flask.request_class flask.wrappers.Request → werkzeug.wrappers.request.Request → werkzeug.sansio.request.Request
Flask.response_class flask.wrappers.Response → werkzeug.wrappers.response.Response → werkzeug.sansio.response.Response
Flask.url_map_class werkzeug.routing.map.Map
Flask.url_rule_class werkzeug.routing.rules.Rule → werkzeug.routing.rules.RuleFactory
应用上的对象来自: {'app.url_map': 'werkzeug.routing.map.Map', 'app.jinja_env': 'flask.templating.Environment', 'app.config': 'flask.config.Config', 'app.session_interface': 'flask.sessions.SecureCookieSessionInterface', 'app.json': 'flask.json.provider.DefaultJSONProvider', 'app.aborter': 'werkzeug.exceptions.Aborter'} 纯 Werkzeug 应用:
1 | from werkzeug.wrappers import Request, Response
2 | from werkzeug.routing import Map, Rule
3 | from werkzeug.exceptions import HTTPException
4 | url_map = Map([Rule("/hello/<name>", endpoint="hello"), Rule("/", endpoint="index")])
5 | @Request.application
6 | def application(request):
7 | adapter = url_map.bind_to_environ(request.environ)
8 | try:
9 | endpoint, args = adapter.match()
10 | return Response(f"{endpoint}: {args or ''} q={request.args.get('q')}")
11 | except HTTPException as e:
12 | return e
GET / → 200 OK | index: q=None
GET /hello/ann?q=1 → 200 OK | hello: {'name': 'ann'} q=1
GET /nope → 404 NOT FOUND | <!doctype html>
<html lang=en>
<title>404 Not Found</title> 纯 Werkzeug 55.1 µs/请求;Flask 73.3 µs/请求;Flask 多出 18.2 µs(约 1.33 倍)——多出来的是上下文推入弹出、会话、钩子、响应转换等
Flask 里有、纯 Werkzeug 里没有的功能(从属性存在性验证):
app.config / 钩子 / 蓝图 / 模板渲染 / session:Flask 对象有 True;纯 Werkzeug 函数有 False