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 
posted @ 2021-03-26 23:30  yangblood  阅读(769)  评论(0编辑  收藏  举报