UNPKG

claude-code-templates

Version:

CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects

384 lines (306 loc) 11.3 kB
# Flask Application Factory Pattern Create a scalable Flask application using the factory pattern with blueprints and configuration management. ## Purpose This command helps you set up a Flask application using the application factory pattern, which is the recommended approach for larger Flask applications. ## Usage ``` /app-factory ``` ## What this command does 1. **Creates application factory** with proper structure 2. **Sets up configuration management** for different environments 3. **Implements blueprints** for modular design 4. **Configures extensions** (database, auth, etc.) 5. **Adds error handling** and logging ## Example Output ```python # app/__init__.py from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_login import LoginManager from flask_mail import Mail from flask_wtf.csrf import CSRFProtect from flask_cors import CORS import logging from logging.handlers import RotatingFileHandler import os # Initialize extensions db = SQLAlchemy() migrate = Migrate() login = LoginManager() mail = Mail() csrf = CSRFProtect() cors = CORS() def create_app(config_class=None): """Application factory function.""" app = Flask(__name__) # Load configuration if config_class is None: config_class = os.environ.get('FLASK_CONFIG', 'development') if isinstance(config_class, str): from app.config import config app.config.from_object(config[config_class]) else: app.config.from_object(config_class) # Initialize extensions db.init_app(app) migrate.init_app(app, db) login.init_app(app) mail.init_app(app) csrf.init_app(app) cors.init_app(app) # Configure login manager login.login_view = 'auth.login' login.login_message = 'Please log in to access this page.' login.login_message_category = 'info' # Register blueprints from app.main import bp as main_bp app.register_blueprint(main_bp) from app.auth import bp as auth_bp app.register_blueprint(auth_bp, url_prefix='/auth') from app.api import bp as api_bp app.register_blueprint(api_bp, url_prefix='/api') from app.admin import bp as admin_bp app.register_blueprint(admin_bp, url_prefix='/admin') # Error handlers from app.errors import bp as errors_bp app.register_blueprint(errors_bp) # Configure logging if not app.debug and not app.testing: if not os.path.exists('logs'): os.mkdir('logs') file_handler = RotatingFileHandler( 'logs/app.log', maxBytes=10240, backupCount=10 ) file_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]' )) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) app.logger.setLevel(logging.INFO) app.logger.info('Flask application startup') return app # Import models (avoid circular imports) from app import models ``` ```python # app/config.py import os from dotenv import load_dotenv basedir = os.path.abspath(os.path.dirname(__file__)) load_dotenv(os.path.join(basedir, '.env')) class Config: """Base configuration class.""" SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key' SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'app.db') SQLALCHEMY_TRACK_MODIFICATIONS = False # Mail configuration MAIL_SERVER = os.environ.get('MAIL_SERVER') MAIL_PORT = int(os.environ.get('MAIL_PORT') or 587) MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true').lower() in ['true', 'on', '1'] MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') ADMIN_EMAIL = os.environ.get('ADMIN_EMAIL') # Pagination POSTS_PER_PAGE = 10 USERS_PER_PAGE = 50 # Upload configuration MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB UPLOAD_FOLDER = os.path.join(basedir, 'uploads') @staticmethod def init_app(app): pass class DevelopmentConfig(Config): """Development configuration.""" DEBUG = True SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'app-dev.db') class TestingConfig(Config): """Testing configuration.""" TESTING = True SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or 'sqlite://' WTF_CSRF_ENABLED = False class ProductionConfig(Config): """Production configuration.""" SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'app.db') @classmethod def init_app(cls, app): Config.init_app(app) # Log to stderr import logging from logging import StreamHandler file_handler = StreamHandler() file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) config = { 'development': DevelopmentConfig, 'testing': TestingConfig, 'production': ProductionConfig, 'default': DevelopmentConfig } ``` ```python # app/main/__init__.py from flask import Blueprint bp = Blueprint('main', __name__) from app.main import routes ``` ```python # app/main/routes.py from flask import render_template, request, current_app from app.main import bp from app.models import Post @bp.route('/') @bp.route('/index') def index(): """Home page.""" page = request.args.get('page', 1, type=int) posts = Post.query.filter_by(published=True).order_by( Post.created_at.desc() ).paginate( page=page, per_page=current_app.config['POSTS_PER_PAGE'], error_out=False ) return render_template('index.html', posts=posts) @bp.route('/about') def about(): """About page.""" return render_template('about.html') ``` ```python # app/auth/__init__.py from flask import Blueprint bp = Blueprint('auth', __name__) from app.auth import routes ``` ```python # app/auth/routes.py from flask import render_template, redirect, url_for, flash, request from flask_login import login_user, logout_user, login_required, current_user from werkzeug.urls import url_parse from app import db from app.auth import bp from app.auth.forms import LoginForm, RegistrationForm from app.models import User @bp.route('/login', methods=['GET', 'POST']) def login(): """User login.""" if current_user.is_authenticated: return redirect(url_for('main.index')) form = LoginForm() if form.validate_on_submit(): user = User.query.filter_by(username=form.username.data).first() if user is None or not user.check_password(form.password.data): flash('Invalid username or password', 'error') return redirect(url_for('auth.login')) login_user(user, remember=form.remember_me.data) next_page = request.args.get('next') if not next_page or url_parse(next_page).netloc != '': next_page = url_for('main.index') return redirect(next_page) return render_template('auth/login.html', form=form) @bp.route('/logout') @login_required def logout(): """User logout.""" logout_user() flash('You have been logged out.', 'info') return redirect(url_for('main.index')) @bp.route('/register', methods=['GET', 'POST']) def register(): """User registration.""" if current_user.is_authenticated: return redirect(url_for('main.index')) form = RegistrationForm() if form.validate_on_submit(): user = User(username=form.username.data, email=form.email.data) user.set_password(form.password.data) db.session.add(user) db.session.commit() flash('Registration successful!', 'success') return redirect(url_for('auth.login')) return render_template('auth/register.html', form=form) ``` ```python # app/models.py from app import db, login from werkzeug.security import generate_password_hash, check_password_hash from flask_login import UserMixin from datetime import datetime class User(UserMixin, db.Model): """User model.""" id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), index=True, unique=True) email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) created_at = db.Column(db.DateTime, index=True, default=datetime.utcnow) posts = db.relationship('Post', backref='author', lazy='dynamic') def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) def __repr__(self): return f'<User {self.username}>' @login.user_loader def load_user(id): return User.query.get(int(id)) class Post(db.Model): """Post model.""" id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) content = db.Column(db.Text, nullable=False) published = db.Column(db.Boolean, default=False) created_at = db.Column(db.DateTime, index=True, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) def __repr__(self): return f'<Post {self.title}>' ``` ```python # app.py (main application entry point) from app import create_app, db from app.models import User, Post app = create_app() @app.shell_context_processor def make_shell_context(): """Add models to shell context.""" return {'db': db, 'User': User, 'Post': Post} if __name__ == '__main__': app.run(debug=True) ``` ## Project Structure ``` project/ ├── app/ │ ├── __init__.py # Application factory │ ├── config.py # Configuration classes │ ├── models.py # Database models │ ├── main/ │ │ ├── __init__.py # Main blueprint │ │ └── routes.py # Main routes │ ├── auth/ │ │ ├── __init__.py # Auth blueprint │ │ ├── routes.py # Auth routes │ │ └── forms.py # Auth forms │ ├── api/ │ │ ├── __init__.py # API blueprint │ │ └── routes.py # API routes │ └── templates/ # Jinja2 templates ├── migrations/ # Database migrations ├── logs/ # Application logs ├── app.py # Application entry point ├── requirements.txt # Dependencies └── .env # Environment variables ``` ## Benefits of Application Factory - **Testing**: Easy to create app instances with different configs - **Scalability**: Modular design with blueprints - **Configuration**: Environment-specific settings - **Extensions**: Proper initialization order - **Maintainability**: Clear separation of concerns