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