Flask アプリケーションが成長するにつれ、単一ファイルでは管理が困難になる。大規模アプリケーションを設計するためのパターンを紹介する。
アプリケーションファクトリパターン
create_app 関数でアプリケーションを生成する。これにより循環インポートを回避し、テスト時に異なる設定を渡せる。
# app/__init__.py
from flask import Flask
def create_app(config_name='default'):
app = Flask(__name__)
app.config.from_object(f'config.{config_name}')
# 拡張の初期化
from app.extensions import db, migrate, login_manager
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
# Blueprint の登録
from app.views import main_bp, api_bp, admin_bp
app.register_blueprint(main_bp)
app.register_blueprint(api_bp, url_prefix='/api')
app.register_blueprint(admin_bp, url_prefix='/admin')
return app
推奨ディレクトリ構成
拡張の分離
拡張は extensions.py でインスタンス化し、create_app 内で init_app を呼ぶ。
# app/extensions.py
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
db = SQLAlchemy()
migrate = Migrate()
login_manager = LoginManager()
サービス層の導入
ビュー関数にビジネスロジックを書かず、サービス層に分離する。
# app/services/user_service.py
from app.models import User
from app.extensions import db
class UserService:
@staticmethod
def create_user(username, email, password):
user = User(username=username, email=email)
user.set_password(password)
db.session.add(user)
db.session.commit()
return user
@staticmethod
def get_by_email(email):
return User.query.filter_by(email=email).first()
# app/views/main.py
from app.services.user_service import UserService
@main_bp.route('/register', methods=['POST'])
def register():
user = UserService.create_user(
request.form['username'],
request.form['email'],
request.form['password']
)
return redirect(url_for('main.login'))
設定の環境別管理
# config.py
import os
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev')
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'
class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
default = DevelopmentConfig
これらのパターンを組み合わせることで、保守性とテスタビリティの高いアプリケーションを構築できる。