轻量级的Web框架Flask 中模块化应用的实现


Posted in Python onSeptember 11, 2017

Flask是一个轻量级的Web框架。虽然是轻量级的,但是对于组件一个大型的、模块化应用也是能够实现的,“蓝图”就是这样一种实现。对于模块化应用的实现,在Flask 0.2版本中进行了设计。本文暂时不对“蓝图”做详细的介绍,而是先从0.2版本中的Module类的实现讲起。其实,“蓝图”的实现和Module类的实现很相似。

为什么实现模块化应用

对于大型应用而言,随着功能的不断增加,整个应用的规模也会扩大。按照一定的规则将应用的不同部分进行模块化,不仅能够使整个应用逻辑清晰,也易于维护。例如,在Flask中,你也许想像如下构建一个简单的项目:

/myapplication
  /__init__.py
  /views
    /__init__.py
    /admin.py
    /frontend.py

以上目录结构中,我们将之前的Flask单文件修改成了一个应用包,所有的视图函数都在views下,并且按照功能分为了admin和frontend两个部分。为了实现这种模块化应用的构建,在0.2版本中Flask实现了Module类。这个类实例可以通过注册的方式,在Flask应用创建后添加进应用。

Module类实现了一系列的方法:

•route(rule, **options)
•add_url_rule(rule, endpoint, view_func=None, **options)
•before_request(f)
•before_app_request(f)
•after_request(f)
•after_app_request(f)
•context_processor(f)
•app_context_processor(f)
•_record(func)

以上方法除了add_url_rule和_record外,都可以作为装饰器在自己的模块中使用,这些装饰器都返回一个函数。通过调用_record方法,可以将装饰器返回的函数放到_register_events中。当Flask应用创建之后,通过运行_register_events列表中的函数,可以将这个模块注册到应用中去。

Flask应用怎么注册一个Module

以下我们以一个例子来说明Flask应用怎么注册一个Module。

1. 项目结构

这个简单的例子项目结构如下:

/myapplication
  /__init__.py
  /app.py
  /views
    /__init__.py
    /admin.py
    /blog.py

admin.py和blog.py两个模块的代码如下:

# admin.py
from flask import Module
admin = Module(__name__)
@admin.route('/')
def index():
  return "This is admin page!"
@admin.route('/profile')
def profile():
  return "This is profile page."
# blog.py
from flask import Module
blog = Module(__name__)
@blog.route('/')
def index():
  return "This is my blog!"
@blog.route('/article/<int:id>')
def article(id):
  return "The article id is %d." % id

以上两个模块中,我们首先分别创建了一个Module类,然后像写一般的视图函数一样,为每个模块增加一些规则。之后,可以在创建Flask应用的时候将这些模块引入,就可以注册了。

# app.py
from flask import Flask
from views.admin import admin
from views.blog import blog
app = Flask(__name__)
@app.route('/')
def index():
  return "This is my app."
app.register_module(blog, url_prefix='/blog')
app.register_module(admin, url_prefix='/admin')
if __name__ == '__main__':
  from werkzeug.serving import run_simple
  run_simple('localhost', 5000, app)

在app.py中:

•我们首先引入了admin和blog两个Module对象;
•之后,我们创建了一个Flask应用app,并且为这个应用增加了一个视图函数;
•为了注册模块,我们调用了应用的register_module方法;
•最后,从werkzeug.serving中我们调用run_simple方法,用来创建一个本地的服务器用于测试这个Flask应用。

根据以上的步骤,我们就可以测试这个应用。分别以/blog和/admin为URL前缀,就可以访问blog和admin两个模块了。

2. 注册Module时发生了什么

根据上面的例子,只要简单的调用Flask应用的register_module方法,就可以注册一个Module了。关于register_module方法的代码如下:

def register_module(self, module, **options):
  """Registers a module with this application. The keyword argument
  of this function are the same as the ones for the constructor of the
  :class:`Module` class and will override the values of the module if
  provided.
  """
  options.setdefault('url_prefix', module.url_prefix)
  state = _ModuleSetupState(self, **options)
  for func in module._register_events:
    func(state)

通过以上代码可以发现:
•可以通过增加url_prefix来区分不同的Module,这在app注册admin和blog时我们已经看到了;
•在注册时,我们创建了一个_ModuleSetupState的类,这个类接收Flask应用和一些参数生成一个state实例。这个实例反映了当前Flask应用的状态。
•前面在讲到Module类的时候,我们讲到Module未注册时会将自己模块的一些功能实现都放在_register_events列表中,这些功能实现都是函数形式。当需要将模块注册到某一应用上时,只需要传递关于这个应用信息的参数即可,即就是上面的state实例。这样,通过运行函数,可以讲一些属性绑定到当前应用上去。

以上面例子中不同模块的URL绑定来讲,通过注册,应用app现形成了如下的URL“地图”:

>>> app.url_map
Map([<Rule '/admin/profile' (HEAD, GET) -> admin.profile>,
   <Rule '/admin/' (HEAD, GET) -> admin.index>,
   <Rule '/blog/' (HEAD, GET) -> blog.index>,
   <Rule '/' (HEAD, GET) -> index>,
   <Rule '/blog/article/<id>' (HEAD, GET) -> blog.article>,
   <Rule '/static/<filename>' (HEAD, GET) -> static>]
  )
>>> app.url_map._rules_by_endpoint
{'admin.index': [<Rule '/admin/' (HEAD, GET) -> admin.index>],
 'admin.profile': [<Rule '/admin/profile' (HEAD, GET) -> admin.profile>],
 'blog.article': [<Rule '/blog/article/<id>' (HEAD, GET) -> blog.article>],
 'blog.index': [<Rule '/blog/' (HEAD, GET) -> blog.index>],
 'index': [<Rule '/' (HEAD, GET) -> index>],
 'static': [<Rule '/static/<filename>' (HEAD, GET) -> static>]
}
>>> app.view_functions
{'admin.index': <function views.admin.index>,
 'admin.profile': <function views.admin.profile>,
 'blog.article': <function views.blog.article>,
 'blog.index': <function views.blog.index>,
 'index': <function __main__.index>
}

这样,就可以把不同模块的URL规则放在一起,并在endpoint和视图函数之间形成对应关系。关于Flask应用中URL处理,可以参考:Flask应用中的URL处理。

Python 相关文章推荐
Python实现将n个点均匀地分布在球面上的方法
Mar 12 Python
浅谈Python的文件类型
May 30 Python
python利用dir函数查看类中所有成员函数示例代码
Sep 08 Python
python 判断网络连通的实现方法
Apr 22 Python
Python中的单行、多行、中文注释方法
Jul 19 Python
元组列表字典(莫烦python基础)
Apr 03 Python
Python Pandas实现数据分组求平均值并填充nan的示例
Jul 04 Python
python代码实现逻辑回归logistic原理
Aug 07 Python
在Python中等距取出一个数组其中n个数的实现方式
Nov 27 Python
浅谈TensorFlow中读取图像数据的三种方式
Jun 30 Python
基于python爬取梨视频实现过程解析
Nov 09 Python
python批量创建变量并赋值操作
Jun 03 Python
Python 模拟购物车的实例讲解
Sep 11 #Python
python添加模块搜索路径方法
Sep 11 #Python
解决Django模板无法使用perms变量问题的方法
Sep 10 #Python
python实现批量修改文件名代码
Sep 10 #Python
python中利用队列asyncio.Queue进行通讯详解
Sep 10 #Python
Python上下文管理器和with块详解
Sep 09 #Python
Python使用asyncio包处理并发详解
Sep 09 #Python
You might like
Views rows style模板重写代码
2011/05/16 PHP
php导入模块文件分享
2015/03/17 PHP
php session 写入数据库
2016/02/13 PHP
基于jquery.Jcrop的头像编辑器
2010/03/01 Javascript
推荐10个超棒的jQuery工具提示插件
2011/10/11 Javascript
jQuery中对节点进行操作的相关介绍
2013/04/16 Javascript
使图片旋转的3种解决方案
2013/11/21 Javascript
jquery统计输入文字的个数并对其进行判断
2014/01/07 Javascript
JavaScript快速切换繁体中文和简体中文的方法及网站支持简繁体切换的绝招
2016/03/07 Javascript
详解wow.js中各种特效对应的类名
2017/09/13 Javascript
js中json对象和字符串的理解及相互转化操作实现方法
2017/09/22 Javascript
Vue.js实现分页查询功能
2020/11/15 Javascript
vue 注册组件的使用详解
2018/05/05 Javascript
Vue-cli3项目配置Vue.config.js实战记录
2018/07/29 Javascript
为vue项目自动设置请求状态的配置方法
2019/06/09 Javascript
用Golang运行JavaScript的实现示例
2019/11/25 Javascript
Python抓取Discuz!用户名脚本代码
2013/12/30 Python
Python生成pdf文件的方法
2014/08/04 Python
神经网络理论基础及Python实现详解
2017/12/15 Python
python 实现求解字符串集的最长公共前缀方法
2018/07/20 Python
Python 使用类写装饰器的小技巧
2018/09/30 Python
Anaconda3+tensorflow2.0.0+PyCharm安装与环境搭建(图文)
2020/02/18 Python
python保留格式汇总各部门excel内容的实现思路
2020/06/01 Python
python3 循环读取excel文件并写入json操作
2020/07/14 Python
Python+MySQL随机试卷及答案生成程序的示例代码
2021/02/01 Python
使用html2canvas.js实现页面截图并显示或上传的示例代码
2018/12/18 HTML / CSS
美国最大的香水连锁店官网:Perfumania
2016/08/15 全球购物
Jabra捷波朗美国官网:用于办公、车载和运动的无线蓝牙耳麦
2017/02/01 全球购物
台湾线上百货零售购物平台:friDay购物
2017/08/18 全球购物
数学高效课堂实施方案
2014/03/29 职场文书
公务员爱岗敬业演讲稿
2014/08/26 职场文书
医院领导班子整改方案
2014/10/01 职场文书
学院党的群众路线教育实践活动第一阶段情况汇报
2014/10/25 职场文书
为自己工作观后感
2015/06/11 职场文书
如何书写公司员工保密协议?
2019/06/27 职场文书
Nginx流量拷贝ngx_http_mirror_module模块使用方法详解
2022/04/07 Servers