🐛 Типичные ошибки: Flask-проект

⚡ Топ-3 ошибки

  1. Забыть db.session.commit() — изменения не сохранятся.
  2. Зарегистрировать Blueprint без url_prefix — маршруты конфликтуют.
  3. Circular import: импортировать db из модуля, который сам импортирует модели.

1. Забытый db.session.commit()

Неправильно

question = Question(text="Новый вопрос")
db.session.add(question)
# commit() забыт!
return jsonify({"id": question.id})

Правильно

question = Question(text="Новый вопрос")
db.session.add(question)
db.session.commit()  # сохраняет изменения в БД
return jsonify({"id": question.id})

Последствие: объект добавлен в сессию, но не сохранён в базу данных. После перезапуска приложения данные исчезнут. Кроме того, question.id может быть None до commit.

2. Blueprint без url_prefix — конфликт маршрутов

Неправильно

# questions_bp.route('/questions')
# responses_bp.route('/responses')
# Регистрация БЕЗ префикса:
app.register_blueprint(questions_bp)
app.register_blueprint(responses_bp)

Правильно

app.register_blueprint(questions_bp, url_prefix='/questions')
app.register_blueprint(responses_bp, url_prefix='/responses')

Последствие без префикса: если в Blueprint маршруты определены как /, то все Blueprint будут отвечать на один URL, и Flask выдаст ошибку или последний Blueprint перекроет предыдущий.

3. Circular import — циклический импорт

Неправильно

# app/__init__.py
from flask_sqlalchemy import SQLAlchemy
from app.models.questions import Question  # импорт здесь

db = SQLAlchemy()

# app/models/questions.py
from app import db  # импортирует app/__init__.py
                     # который пытается импортировать Question
                     # ЦИКЛ!

Правильно

# app/__init__.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()  # db определён здесь

def create_app():
    app = Flask(__name__)
    db.init_app(app)
    from app.routers.questions import questions_bp  # импорт ВНУТРИ функции
    app.register_blueprint(questions_bp, url_prefix='/questions')
    return app

# app/models/questions.py
from app import db  # безопасно — db уже определён, create_app не вызван

Решение: импортировать blueprints внутри функции create_app(), после инициализации расширений.

4. Инициализация db вне Application Context

Ошибка

RuntimeError: No application found. Either work inside
a view function or push an application context with
app.app_context().
# Попытка создать таблицы без контекста:
from app import db
db.create_all()  # ошибка!

Правильно

from app import create_app, db

app = create_app()
with app.app_context():
    db.create_all()  # внутри контекста — работает

Flask-расширения требуют активного контекста приложения для работы с БД.

5. Возврат Python-объекта вместо jsonify

Неправильно

@questions_bp.route('/')
def list_questions():
    questions = db.session.scalars(select(Question)).all()
    return questions  # TypeError: объект SQLAlchemy не сериализуем

Правильно

@questions_bp.route('/')
def list_questions():
    questions = db.session.scalars(select(Question)).all()
    result = [QuestionOut.model_validate(q).model_dump() for q in questions]
    return jsonify(result)

ORM-объекты нельзя передавать напрямую в ответ. Нужно сериализовать через Pydantic или вручную создать словарь.

6. Дублирование имён Blueprint

Неправильно

questions_bp = Blueprint('api', __name__)
responses_bp = Blueprint('api', __name__)  # то же имя!
# ValueError: The name 'api' is already registered

Правильно

questions_bp = Blueprint('questions', __name__)
responses_bp = Blueprint('responses', __name__)  # уникальные имена

7. request.get_json() возвращает None

Ошибка

# При вызове POST без заголовка Content-Type: application/json
data = request.get_json()
data['text']  # TypeError: 'NoneType' object is not subscriptable

Правильно

data = request.get_json()
if not data:
    return jsonify({"error": "JSON body required"}), 400

# Или с silent=False для явной ошибки:
data = request.get_json(force=True, silent=False)

Всегда проверяйте, что клиент передал Content-Type: application/json и тело не пустое.