⚖️ Старый vs Новый: паттерны Flask

Паттерны из лекции (устаревшие) → современные практики Flask 3.x

⚡ Главные отличия

  • Лекция: app = Flask(__name__) напрямую → современно: def create_app()
  • Лекция: db = SQLAlchemy(app) → современно: db.init_app(app)
  • Лекция: FLASK_ENV → современно: FLASK_DEBUG или кастомная переменная

1. Инициализация приложения и БД

Из лекции (старое)

# run.py — всё в одном файле
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import DevelopmentConfig

app = Flask(__name__)
app.config.from_object(DevelopmentConfig)
db = SQLAlchemy(app)  # привязка при создании

Проблема: db привязан к одному экземпляру app. При тестировании нельзя создать второе приложение с другой конфигурацией. Нарушает принцип Application Factory.

Современный подход (Flask 3.x)

# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()  # без привязки к app

def create_app(config_name='development'):
    app = Flask(__name__)
    from config import config_map
    app.config.from_object(config_map[config_name])
    db.init_app(app)  # привязка при вызове
    return app

Преимущество: можно создать несколько экземпляров приложения (например, для тестов), передавая разную конфигурацию.

2. Переменная окружения для конфигурации

Из лекции (старое)

# использование FLASK_ENV
config_name = os.environ.get('FLASK_ENV', 'development')
config_class = {
    'development': DevelopmentConfig,
    ...
}.get(config_name)
app.config.from_object(config_class)

FLASK_ENV устарела в Flask 2.3 и удалена в Flask 3.0. Использование вызывает предупреждение или ошибку.

Современный подход (Flask 3.x)

# Кастомная переменная окружения
import os

config_name = os.environ.get('APP_ENV', 'development')
app = create_app(config_name)

# Отладочный режим — через FLASK_DEBUG
# export FLASK_DEBUG=1  (bash)
# $env:FLASK_DEBUG=1    (PowerShell)

В Flask 3.x FLASK_DEBUG=1 включает дебаг-режим. Для конфигурации используйте свою переменную (APP_ENV или аналог).

3. Маршруты: прямо в run.py vs Blueprints

Из лекции (старое)

# run.py — маршруты смешаны с конфигурацией
from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
    return "Community Pulse"

@app.route('/questions')
def list_questions():
    ...

@app.route('/questions/add', methods=['POST'])
def add_question():
    ...

Проблема: при росте проекта run.py разрастается. Нет разделения ответственностей. Сложно поддерживать и тестировать.

Современный подход

# app/routers/questions.py
from flask import Blueprint
questions_bp = Blueprint('questions', __name__)

@questions_bp.route('/')
def list_questions(): ...

@questions_bp.route('/', methods=['POST'])
def add_question(): ...

# app/__init__.py
def create_app():
    ...
    app.register_blueprint(
        questions_bp,
        url_prefix='/questions'
    )
    ...

Каждый модуль в своём файле. Легко добавлять новые разделы без изменения основного файла.

4. Запросы к БД: legacy Query API vs select()

Flask-SQLAlchemy 2.x / SQLAlchemy 1.x (устаревшее)

# Из лекции — старый Query API
questions = Question.query.all()
question = Question.query.get(question_id)
questions = Question.query.filter_by(
    text="..."
).first()

.query — устаревший интерфейс. В SQLAlchemy 2.x помечен как deprecated, в будущих версиях может быть удалён.

SQLAlchemy 2.x (современное)

from sqlalchemy import select

# Все объекты
questions = db.session.scalars(
    select(Question)
).all()

# По ID (рекомендованный способ)
question = db.session.get(Question, question_id)

# Фильтрация
from sqlalchemy import select
stmt = select(Question).where(
    Question.text.contains("работа")
)
questions = db.session.scalars(stmt).all()

Современный стиль работает одинаково с SQLAlchemy Core и ORM. Рекомендован для всех новых проектов.

5. Структура проекта

Из лекции (упрощённая)

/community_pulse/
|-- run.py          # всё: app, config, маршруты, модели
|-- config.py

Подходит только для учебного минимума. Не масштабируется.

Рекомендуемая структура из лекции

/community_pulse/
|-- app/
|   |-- __init__.py        # create_app(), db
|   |-- routers/
|   |   |-- questions.py   # Blueprint questions
|   |   |-- responses.py   # Blueprint responses
|   |-- models/
|   |   |-- questions.py   # модель Question
|   |   |-- responses.py   # модель Response
|   |-- schemas/
|       |-- question.py    # Pydantic схемы
|       |-- response.py
|-- config.py
|-- run.py

Структура из лекции — уже хорошая модульная организация. Следуйте ей для реального проекта.