Flask:项目结构
尽管在单个脚本文件中编写小型 Web 应用很方便,但这种方法的伸缩性不好。应用变复杂后,使用单个大型源码文件会导致很多问题。
不同于多数其他的 Web 框架,Flask 并不强制要求大型项目使用特定的组织方式。
1、项目结构
|-flasky
|-app/
|-templates/
|-static/
|-main/
|-__init__.py
|-errors.py
|-forms.py
|-views.py
|-__init__.py
|-email.py
|-models.py
|-migrations/
|-tests/
|-__init__.py
|-test*.py
|-venv/
|-requirements.txt
|-config.py
|-flasky.py
-
Flask 应用一般保存在名为 app 的包中;
-
和之前一样,数据库迁移脚本在 migrations 文件夹中;
-
单元测试在 tests 包中编写;
-
和之前一样,Python 虚拟环境在 venv 文件夹中。
-
requirements.txt 列出了所有依赖包,便于在其他计算机中重新生成相同的虚拟环境;
-
config.py 存储配置;
-
flasky.py 定义 Flask 应用实例,同时还有一些辅助管理应用的任务。
2、配置选项
config.py
:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config():
# session加密密钥
SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
# ...
# 定义init_app() 方法,可以执行更复杂的初始化过程
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
# SQLALCHEMY_DATABASE_URI = ...
class TestingConfig(Config):
TESTING = True
# SQLALCHEMY_DATABASE_URI = ...
class ProductionConfig(Config):
# SQLALCHEMY_DATABASE_URI = ...
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
3、使用工厂函数
app/__init__.py
:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# ...
from config import config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
# init_app() 方法,用于执行更复杂的初始化过程
config[config_name].init_app(app)
db.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/auth')
return app
4、使用蓝图
main/__init__.py
:
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
main/views.py
:
from . import main
# ...
@main.route('/')
def index():
# ...
模板中、views.py 中的url_for()函数要使用 'main.login'
5、应用脚本
flasky.py
:
import os
from app import create_app, db
from app.models import User, Role
from flask_migrate import Migrate
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
migrate = Migrate(app, db)
@app.shell_context_processor
def make_shell_context():
return dict(db=db, User=User, Role=Role)
6、单元测试
tests/test_basics.py
:
import unittest
from flask import current_app
from app import create_app, db
class BasicsTestCase(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_app_exists(self):
self.assertFalse(current_app is None)
def test_app_is_testing(self):
self.assertTrue(current_app.config['TESTING'])
flasky.py
:
# ...
@app.cli.command()
def test():
"""Run the unit tests."""
import unittest
tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner(verbosity=2).run(tests)
$ flask test