1. 对于django来说,内部组件特别多,自身功能强大,有点大而全,而flask,内置组件很少,但是它的第三方组件很多,
扩展性强,有点短小精悍,而它们之间也有相似之处,
因为它们两个框架都没有写sockte,都是基于wsgi协议做的,在此之外,flask框架中的上下文管理较为耀眼。
相同点:它们两个框架都没有写sockte,都是基于wsgi协议做的
请求相关数据传递的方式不同:django:通过传递request参数取值
flask: request的模块
组件不同:django组件多
flask组件少,第三方组件丰富
注意: 使用上下文管理机制
-threading.local()/greenlet.get_current()?---》Local的作用?
作用:为每个线/携程程创建一个独立的空间,使得线程对自己空间中的数据进行操作(数据隔离)。
应用:DBUtils中为每个线程创建一个数据库链接时使用
-如何获取一个线程的唯一标记:threading.get_ident()
-再次根据线程唯一标记,设置一个大内存字典的key,值就是线程空间中的数据
-DBUtils线程池的模式也是为每个线程创建一个链接
-SQLAlchemy的create_engine也会创建线程池以供使用
2. session
两个Local和LocalStack分别对应ctx和app_ctx
请求上下文管理(ctx):request,session
应用上下文管理(ap_ctx)
- 请求到来之后wsgi会触发__call__方法,由__call__方法再次调用wsgi_app方法
- 在wsgi_app方法中:
- 首先将 请求相关+空session 封装到一个RequestContext对象中,即:ctx。
- 将ctx交给LocalStack对象,再由LocalStack将ctx添加到Local中,Local大字典结构:
__storage__ = {
1231:{stack:[ctx] }
}
- 根据请求中的cookie中提取名称为session_id对应的值,对cookie进行加密+反序列化,再次赋值给ctx中的session
-> LocalStack获取Local中的数据后,视图函数通过LocalProxy,获取LocalStack中相对应的值
- 增删改查
- 把session中的数据再次写入到cookie中。
- 将ctx删除
- 结果返回给用户浏览器
- 断开socket连接
3. 问题:
为什么要把 ctx=request/session app_ctx = app/g 分开?
答:编写离线脚本时,需要配置文件,而配置文件存放在app中,并不需要请求相关数据
所以把app和请求相关的数据分开。如果只是需要g传递数据,则在g的生命周期中完全够用
在web runtime时,栈中永远只有一个ctx,或者app_ctx;
在使用离线脚本时,则可能存在多个,但是数据并不会混杂,通过with语句和top取值(-1)可以分层次获取
4. Flask中g的生命周期?
在请求触发__call__调用wsgi_app时,生成app_ctx=AppContext(app,g)
在请求结束时app_ctx.pop()结束g
5. g和session一样吗?
g是在有请求时被创建,请求结束时删除,下次请求又是一个新的g
session会被加密序列化写入用户cookie,下次请求解密反序列化就有
6. g和全局变量一样吗?
全局变量在程序启动时只生成一次,有且只有这一个变量
g在请求时被生成,请求结束时被删除,是临时可创建变量
7.依赖的wsgi(服务器网关接口): werkzurg
8. 配置文件
可以设置一个跟Django差不多的settings配置文件,通过app.config.from_object("settings.xxx")路径,
具体实现是通过importlib模块和getattr反射找到“字符串路径”,再引用配置相关信息
9. 路由系统
-基于装饰器实现的路由系统
-endpoint,反向生成URL,默认函数名
-url_for("函数名" or endpoint)--------注意endpoint反向生成url时有同名,
需要导入import functools -> @functools.wraps(func) 保留原函数的原信息
-functool.partial 偏函数(减少用户输入函数参数)
-动态路由:@app.route("/index/<int:nid>") 传递参数使用
10. 视图
-基于反射区别method请求
-FBV
路由设置:@app.route("/xxxx")
-CBV
methods = ["GET",] decorators = ["wrapper"]
路由设置:app.add_url_rule("/xxx", None, UserView.as_view('aaa'))
11. 请求相关
# 请求相关信息
# request.method request.path
# request.args request.full_path
# request.form request.url
# request.values request.files
# request.cookies request.headers
12. 响应
响应体:
return "字符串" return jsonify({"k1": "v1"})
return render_template("xx.html")
return redirect("/xxxx")
定制响应体:
-面向对象的封装
obj = make_response("字符串")
obj.headers["k1"] = "v1"
obj.set_cookie("key", "value")
return obj
设置全局访问权限:
@app.before_request
def xxx():
if request.path == '/login':
return None
if session.get('user'):
return None
return redirect('/login')
13. 模板渲染
-基本数据类型:可以执行python语法
-传入函数:
-django, 自动执行
-flask, 需要手动加括号执行
-全局定义函数
@app.template_global()
def xx(a1, a2):
# {{sb(1,9)}}
return a1 + a2
-添加撒选条件
@app.template_filter()
def db(a1, a2, a3):
# {{ 1|db(2,3) }}
return a1 + a2 + a3
-模板继承跟django差不多
-预定义模块(不传值看不见,传值就启动)
-安全
- 前端: {{u|safe}}
- 后端: MarkUp("asdf")
14. 闪现
-在session中存储一个数据,读取时通过pop将数据移除,获取的值返回给用户
15. 中间件
- call方法什么时候触发?
- 用户发起请求时,才执行。
16. 蓝图(blueprint)
-目标:给开发者提供目录结构
其他:
- 自定义模板、静态文件
- 某一类url添加前缀
- 给一类url添加before_request
17. 特殊装饰器
-放在列表,循环执行
1. before_request (请求相关)
2. after_request
3. before_first_request
4. template_global (模板相关)
5. template_filter
6. errorhandler (可以自定义错误信息)
18.before_request的执行时机(源码实现:存放在一个列表)Local执行之后,视图执行之前
19. threading.local (DBUtils组件创建一个线程池)
20. 为什么导入request,就可以使用?
每次执行request.xx方法时,会触发LocalProxy对象的__getattr__等方法,由方法每次动态的使用
LocalStack去Local中获取数据。
21.扩展:
1. flask-session
2. DBUtils 其他地方也可以使用
3. wtforms
4. sqlalchemy