轻量级的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构造icmp echo请求和实现网络探测器功能代码分享
Jan 10 Python
利用Python的Flask框架来构建一个简单的数字商品支付解决方案
Mar 31 Python
python Spyder界面无法打开的解决方法
Apr 27 Python
Python实现的根据文件名查找数据文件功能示例
May 02 Python
Python格式化输出字符串方法小结【%与format】
Oct 29 Python
Python字符串通过'+'和join函数拼接新字符串的性能测试比较
Mar 05 Python
对python特殊函数 __call__()的使用详解
Jul 02 Python
Python Threading 线程/互斥锁/死锁/GIL锁
Jul 21 Python
TensorFlow基于MNIST数据集实现车牌识别(初步演示版)
Aug 05 Python
python+openCV调用摄像头拍摄和处理图片的实现
Aug 06 Python
使用 Python 处理3万多条数据只要几秒钟
Jan 19 Python
Django实现将views.py中的数据传递到前端html页面,并展示
Mar 16 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
关于URL最大长度限制的相关资料查证
2014/12/23 PHP
php使用pdo连接mssql server数据库实例
2014/12/25 PHP
php使用substr()和strpos()联合查找字符串中某一特定字符的方法
2015/05/12 PHP
List Installed Hot Fixes
2007/06/12 Javascript
js 表单验证方法(实用)
2009/04/28 Javascript
jquery中的sortable排序之后的保存状态的解决方法
2010/01/28 Javascript
JavaScript CSS修改学习第二章 样式
2010/02/19 Javascript
javascript设计模式 封装和信息隐藏(上)
2012/07/24 Javascript
Jquery实现网页跳转或用命令打开指定网页的解决方法
2013/07/09 Javascript
Js日期选择器并自动加入到输入框中示例代码
2013/08/02 Javascript
深入浅出理解javaScript原型链
2015/05/09 Javascript
js实现精美的银灰色竖排折叠菜单
2015/05/16 Javascript
JavaScript中如何使用cookie实现记住密码功能及cookie相关函数介绍
2016/11/10 Javascript
Vue结合原生js实现自定义组件自动生成示例
2017/01/21 Javascript
原生js实现选项卡功能
2017/03/08 Javascript
微信小程序云开发使用方法新手初体验
2019/05/16 Javascript
七行JSON代码把你的网站变成移动应用过程详解
2019/07/09 Javascript
微信小程序渲染性能调优小结
2019/07/30 Javascript
vue中音频wavesurfer.js的使用方法
2020/02/20 Vue.js
Jquery Fade用法详解
2020/11/06 jQuery
python中lambda与def用法对比实例分析
2015/04/30 Python
浅谈python多线程和队列管理shell程序
2015/08/04 Python
用python建立两个Y轴的XY曲线图方法
2019/07/08 Python
python批量解压zip文件的方法
2019/08/20 Python
python 获取当前目录下的文件目录和文件名实例代码详解
2020/03/10 Python
10个python3常用排序算法详细说明与实例(快速排序,冒泡排序,桶排序,基数排序,堆排序,希尔排序,归并排序,计数排序)
2020/03/17 Python
从一次项目重构说起CSS3自定义变量在项目的使用方法
2021/03/01 HTML / CSS
PatPat德国:妈妈的每日优惠
2019/10/02 全球购物
幼儿园大班教学反思
2014/02/10 职场文书
应聘护理专业毕业自荐书范文
2014/02/12 职场文书
学校教研活动总结
2014/07/02 职场文书
材料采购员岗位职责
2015/04/03 职场文书
高中生综合素质评价范文
2015/08/18 职场文书
请假条应该怎么写?
2019/06/24 职场文书
详解Java实现数据结构之并查集
2021/06/23 Java/Android
详细了解java监听器和过滤器
2021/07/09 Java/Android