804 字
4 分钟
Flask 的架构升级
2018-01-13

渐进式搭建大型 Flask 应用

hello world#

  • 第一个 flask 应用(这个示例程序还需要templates文件夹存放模板)
# manage.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/hello_world')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)

使用python manage.py可以快速启动服务,但这种服务启动方式只适合开发环境测试,因为存在以下几个问题。

  • flask 的自带服务器不支持多线程,用于多人的环境时很容易发生阻塞
  • 服务因意外崩溃时不会自动重启
  • 一旦你的 shell 关闭,你的服务将被停止。可以使用nohup python manage.py &让服务在后台运行,或者挂一个 screen screen -S pythonServer``python manage.py(这些方案只适用于快速搭建服务,生产环境应该使用服务器)

扩展#

随着功能的增加,必须根据不同功能把程序拆分成文件,使用manage.py作为入口,在views.py处理路由,在errors.py中处理错误。项目结构修改为这样:

proj
│  manage.py  # 应用入口

├─app
│  errors.py  # 错误处理
│  utils.py  # 工具类
│  views.py  # 视图/路由
│  __init__.py

├─templates  # 模板文件夹
│  about.html
│  index.html
│  login.html

└─static  # 静态资源
   app.js
   app.css

查缺补漏#

  • 服务器 在生产环境使用 web 服务器。如 Nginx, Gunicorn, Tornado
  • 管理服务 使用supervisor, systemd等方式保证服务可靠运行
  • 日志 为了快速定位 bug 以及溯源异常信息,需要使用日志模块输出日志而不是简单地使用print('errorInfo')这种方式 debug, 常用的日志模块有log4j
  • 配置文件 方便切换开发环境和生产环境配置
  • 测试
  • 版本控制 开发必备,不多说,使用Git吧,还建议使用贴近项目的工作流Git 工作流程

更大、更复杂#

利用蓝图和 flask 强大的扩展能力,创建更大的项目

proj
  │-app/
    │-templates/
    │-static/
    │-main/
      │-__init__.py
      │-errors.py
      │-forms.py
      │-views.py
    │-auth/
      │-__init__.py
      │-forms.py
      │-views.py
    │-__init__.py
    │-email.py
    │-models.py
  │-migrations/
  │-tests/
    │-__init__.py
    │-test*.py
  │-venv/
  │-requirements.txt
  │-config.py
  │-manage.py

应用细节#

  • manage.py主入口
#!/usr/bin/python
# -*- coding:utf-8 -*-
import os
from app import create_app

# 配置
config_name = os.getenv('FLASK_CONFIG') or 'default'
app = create_app(config_name)

# gunicorn -k gevent -w 8 -b 127.0.0.1:5000 manage:app
if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5000, debug=True)
  • config.py配置文件
# -*- coding:utf-8 -*-

class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'

    @staticmethod
    def init_app(app):
        pass

class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config):
    DEBUG = True

class TestingConfig(Config):
    TESTING = True

config={
    'dev':DevelopmentConfig,
    'test':TestingConfig,
    'prod':ProductionConfig,
    'default':DevelopmentConfig
    }
  • app/__init__.pyapp 工厂函数,根据不同环境配置初始化 app
#!/usr/bin/python
# -*- coding:utf-8 -*-
from flask import Flask
from config import config

def create_app(config_name):
    app=Flask(__name__)

    # 加载配置
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    # 注册蓝图
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    app.logger.debug('应用初始化完成') # DEBUG
    return app
  • app/main/__init__.py 蓝图
# -*- coding:utf-8 -*-
from flask import Blueprint

main = Blueprint('main', __name__)
  • app/main/views.py 蓝图的视图
# -*- coding:utf-8 -*-
from flask import current_app as app
from . import main

# 测试接口
@main.route('/')
def index():
    app.logger.debug('SUCCESS') # DEBUG
    return 'Hello'

其他#

  • 前后端分离
  • 缓存
  • 权限管理
  • 访客分析
  • 服务器监控
  • 负载均衡
  • CDN
  • 分布式
  • CICD
  • Python venv 虚拟环境
  • ……

最后#

在搭建项目的时候根据自己项目实际情况,选择合适的架构才是正确的选择。

参考文献#

Flask 的架构升级
https://www.waterwater.moe/posts/2018/2018-01-13_flask的架构升级/
作者
whitewater
发布于
2018-01-13
许可协议
CC BY-NC-SA 4.0