Flask - Bonnes Pratiques

Guide des meilleures pratiques pour développer des applications Flask robustes et maintenables.

Structure du Projet

project/
├── app/
│   ├── __init__.py      # Application factory
│   ├── models/          # Modèles de données
│   ├── views/           # Routes et vues
│   ├── templates/       # Templates Jinja2
│   ├── static/         # Assets statiques
│   └── utils/          # Utilitaires
├── tests/              # Tests unitaires
├── config.py           # Configuration
├── requirements.txt    # Dépendances
└── run.py             # Point d'entrée

Application Factory

# app/__init__.py
def create_app(config_name='default'):
    app = Flask(__name__)

    # Charger la configuration
    app.config.from_object(config[config_name])

    # Initialiser les extensions
    db.init_app(app)
    login_manager.init_app(app)

    # Enregistrer les blueprints
    from .views import main
    app.register_blueprint(main)

    return app

Sécurité

Protection CSRF

from flask_wtf.csrf import CSRFProtect

csrf = CSRFProtect()

# Dans les formulaires
class MonFormulaire(FlaskForm):
    # Le token CSRF est automatiquement ajouté

Sécurisation des Headers

from flask_talisman import Talisman

Talisman(app,
    force_https=True,
    content_security_policy={
        'default-src': "'self'",
        'script-src': "'self'"
    })

Gestion des erreurs

class ConfigError(Exception):
    """Erreur de configuration."""
    pass

@app.errorhandler(404)
def not_found_error(error):
    return render_template('404.html'), 404

@app.errorhandler(500)
def internal_error(error):
    db.session.rollback()
    return render_template('500.html'), 500

# Logging
import logging
logger = logging.getLogger(__name__)

@app.before_first_request
def setup_logging():
    if not app.debug:
        # Configuration du logging
        handler = logging.FileHandler('app.log')
        handler.setLevel(logging.INFO)
        app.logger.addHandler(handler)

Tests

import pytest
from app import create_app, db

@pytest.fixture
def app():
    app = create_app('testing')
    with app.app_context():
        db.create_all()
        yield app
        db.drop_all()

@pytest.fixture
def client(app):
    return app.test_client()

Performance

  • Caching
    from flask_caching import Cache
    
    cache = Cache(config={'CACHE_TYPE': 'redis'})
    
    @cache.memoize(timeout=300)
    def get_user(user_id):
        return User.query.get(user_id)
  • Optimisation des requêtes
    # Eager loading
    posts = Post.query.options(
        joinedload('author')
    ).all()

À faire et à ne pas faire

✅ Bonnes pratiques

  • Utiliser une application factory
  • Séparer la configuration par environnement
  • Utiliser des blueprints pour la modularité
  • Implémenter des tests unitaires
  • Gérer proprement les erreurs

❌ À éviter

  • Variables globales pour l'état de l'application
  • Mélanger la logique métier et les vues
  • Négliger la sécurité (CSRF, XSS)
  • Code dupliqué entre les routes
  • Sessions non sécurisées