你所需要的,不仅仅是一个好用的代理。
Flask是一个优秀的Web框架,很多人说它好,但是95%的人其实是在人云亦云,不去读它的源码、不了解作者其他项目、不深入使用很难真的理解它的好。我试着介绍下它备受好评的一些原因:
1. 文档和snippets。文档算是非常好了,基本上你应该知道的都用比较通俗易懂的方式传达给你了,还会告诉你应该怎么设计。但是其实我还想说的是 http://flask.pocoo.org/snippets/,对于文档不满足的其实作者和一些深度用户都已经给了方案,比如会话(session),有专门的分类http://flask.pocoo.org/snippets/category/sessions/,想了解怎么个Redis集成,直接看http://flask.pocoo.org/snippets/75/就好了。
2. 设计哲学。Flask和Django甚至在这点上是完全相反的,Flask只愿意提供最小的核心,给你足够的自由,你可以去试试提交PR想加入一些依赖或者对一些你工作中需要的,但是有点小众的功能有多难,很难说服Flask团队的人支持你。但是Flask提供了非常好的扩展系统,哪怕你是一个新手,也能在文档的提示下编写一个可用的扩展。第三方扩展生态环境非常繁盛,但是质量也是参差不齐,考验你的眼力。我觉得大家喜欢Flask的原因之一就是这种设计哲学和Python工程师的气质是有重合的。
3. 装饰器表示路由。第一次看官方的例子,我都目瞪口呆了。原来装饰器可以这样用,逼格比其他的Web框架在我心中高了一点点。
4. Flask的依赖Werkzeug是一个WSGI工具集,Twisted开源的klein也使用了它。它有什么好呢?其中包含了实现非常好的LocalProxy、cached_property、import_string、find_modules、TypeConversionDict等。LocalProxy这种本地代理的思想,给开发者提供了非常大的空间;除了上面提到的还有多种数据结构,可以看werkzeug下的datastructures.py文件,现在我们在不同的项目都会依赖Werkzeug(Web框架并不是Flask),有时候竟然就是为了用cached_property等实现...;那import_string+find_modules能干什么呢? 可以看 「 Flask最佳实践 」,里面有对重构大型项目下多个蓝图(blueprint)的应用。
5. 蓝图(Blueprint)实现了应用的模块化,使用蓝图让应用层次清晰,开发者可以更容易的开发和维护项目。蓝图通常作用于相同的URL前缀,比如/user/:id、/user/profile这样的地址,都以/user开头,那么就可以放在一个模块中。使用register_blueprint注册模块,如果想去掉模块只需要去掉对应的这个注册语句即可,多方便。
6. 上下文(Context)。先看一个示例:
仔细想一下,这里先引用了flask.request,但是直到用户访问/people/的时候才通过request.args.get('name')获得请求的参数值。试想,引用的时候还没有发生这个请求,那么请求上下文是怎么获得的呢?
flask.request就是一个获取名为_request_ctx_stack的栈顶对象的LocalProxy实例:
上述逻辑能正常使用,是因为其流程是这样的:
用户访问产生请求。
在发生请求的过程中向_request_ctx_stack推入这个请求上下文的对象,它会变成栈顶。request就会成为这个请求上下文,也就包含了这次请求相关的信息和数据。
在视图函数中使用request就可以使用request.args.get('name')了。
设想不使用LocalStack和LocalProxy的话,要想让视图函数访问到请求对象只能将其作为参数,一步步传入视图函数中。这样做的缺点是会让每个视图函数都增加一个request参数,而Flask巧妙地使用上下文把某些对象变为全局可访问(实际上是特定环境的局部对象的代理),每个线程看到的上下文对象却是不同的,这样就巧妙地解决了这个问题。