在本文中我将分享我是如何构造Flask应用的,为支持这篇文章我写了一个非常基本的应用程序,随意命名Overholt。如果你打算按我的思路来的话我推荐你在编辑器或浏览器里有一份源码。
Web应用程序可以封装很多不同的功能。通常,当你想到一个Web应用程序,你通常认为是一个用户接口,这个接口生成HTML和JavaScript并显示给浏览器前的用户。然而,Web应用程序可能会无限复杂。例如,一个应用程序可以作为一个backbone.js前端应用的专有JSON API,也可能是一个原生iOS或Android应用程序定制的JSON API,还有其他很多。所以当启动一个项目时我尝试把它作为一个平台而不是一个应用程序,一个平台包含一个或多个应用程序。但话分两端,Overholt的应用程序源代码中这个概念是不太明显。
这个概念支持前面的说法。我在更大平台范围内寻找逻辑环境,换句话说,我试图在各种客户终端处寻找模式。每个上下文间有细微的关系,因此我功能化地封装、配置它们成独立的Flask应用。这些应用程序可以驻留在同一个代码库或被分离。当部署应用时,我使用Werkzeug的分发中间件(DispatcherMiddleware)可以选择独立或合并地部署它们。对于Overholt,这个平台包括两个Flask应用,它们被组织进了两个对立的Python包:overholt.api和overholt.frontend。
我尝试将应用逻辑看成平台的核心“库”,一些开发者称之为“服务”层。不管你怎么称呼它,这层处于数据模型之上并暴露一个用于操纵数据模型的API。这让我可以在平台范围内将常用例程封装起来,使用这种方法也往往导致“瘦”视图函数。换句话说,它让我保持视图函数小巧,集中在将请求数据转换成API服务层接受的对象。Overholt的应用逻辑主要是位于theoverholt.users、overholt.products、andoverholt.stores包中。
视图函数是HTTP请求与应用逻辑交互的地方。其他框架中这一层通常被称为“控制器”或“处理器”,甚至“命令”。就是在这,HTTP请求的数据能够被应用逻辑的API访问和使用。视图函数然后依据应用逻辑的结果生成响应。Overholt中的视图函数使用Blueprints,每个Blueprints在应用的Python包中都有对应的模块,这样模块的例子如:overholt.api.products或者overholt.frontend.dashboard。
Flask并不对开发者强加任何模式与约定。和像Django和Rails等大型框架相比,这就是我喜欢Flask的一个地方。然而,任何开发者都不愿意为他们的Flask应用建立起那些对其它开发者帮倒忙的模式与约定。没有了模式或约定,你的应用就会失去了架构完整性,以及对于他人很难懂。在使用Flask工作了近2年的后,现在我已经建立起了属于我自己的一些模式和约定。下面就是我通常使用的大纲。
工厂模式是在我Flask应用中第一个实现的模式,已经有少量关于应用工厂的文档,但文件的范围是有限的,我相信这是在鼓励这种模式的使用,也就是说,目前还没有一个既定的实施工厂模式的方法。你的应用程序都有自己独特的要求,因此你的工厂方法应该是相适应的。无论你怎样实施工厂方法,在我看来,不论是在生产环境或测试运行中,在不同语境下创建应用程序时它肯定会带给你更多的控制力。
在Overholt源码里你会找到三个不同的工厂方法(factory methods)。每个应用都有一个工厂以及一个被这些独立的应用工厂所共享的额外工厂。共享工厂实例化应用程序以及使用共享配置选项配置应用程序。这些独立的工厂使用专门的配置选项来深度配置应用程序。例如,api应用工厂注册了一个通用的JSONEncoder类以及一些通用的错误处理器来渲染JSON响应。反之,frontend应用工厂则为HTTP响应初始化了一个assets管道和一些通用的错误处理器
模板对于Flask应用十分重要,因为它们允许开发者把相关的endpoints聚合在一起。老实说,没有了模板,我感觉不会再活了。Flask文档提供了最好的概述:模板是什么和为什它们如此有用。因为Armin [@Lesus 注:flask框架之父] 已经把模板解释得很好了,所以我也其它可以说的。在Overholt源码的环境中,每个应用包包含了很多的模块,而每个模块由很多模块实例组成。API应用包含了三个模块:overholt.api.products, overholt.api.stores和 overholt.api.users。frontend应用包含了一个模块:overholt.frontend.dashboard。所有的模板模块都在相同的包中,这样可以在它们对应的应用中使用一个简单的方法来注册它们。在共享的应用工厂中,你应该注意到register_blueprintshelper方法。这个方法只是简单的浏览在应用包中所有的模板模块,然后在app实例上注册它们。
服务就是我遵循的第三大高级概念:“应用逻辑在逻辑包中组织,然后对外暴露它们的API”的方式。它们负责与任何外部数据资源的连接和交互。外部数据资源包含(但是并不局限于)像应用数据库,Amazon的S3服务,或者外部的RESTful API等这些东西。一般来说,每个功能(products, stores,和 users)的逻辑区域都包含了一个或者更多的建立在所需功能的服务。在Overholt源码中,你会发现一个服务的基础类来管理特定的SQLAlchemy model。此外,这个基础类添加了扩展和额外的方法,对外暴露API来支持所需的功能。这最好的例子就是overholt.stores.StoresService类(参考)了。 服务实例类能够随意实例化,但是为了方便实例化,所以都统一到了overholt.services模块中(参考)。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。 2KB翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务