Flask: микрофреймворк для веб-разработки на Python

Раздел: Веб-разработка -> flask

Основы работы с Flask

Наиболее эффективное решение для старта веб-приложения на Flask - минимальный проект с одним маршрутом и шаблоном. Это позволяет быстро увидеть результат и понять архитектуру.

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', title='Главная')

if __name__ == '__main__':
    app.run(debug=True)

фреймворк flask python (фреймворк flask в python)

После запуска по адресу http://127.0.0.1:5000 откроется страница, сгенерированная шаблоном index.html. Режим debug=True позволяет автоматически перезагружать сервер при изменениях кода и показывает подробные сообщения об ошибках.

Типичная ошибка: если папка templates не создана или имя шаблона указано неверно, возникает TemplateNotFound. Решение - создать папку templates в корне проекта и поместить туда файл index.html.

Как передать параметр в маршрут?

@app.route('/user/<username>')
def user_profile(username):
    return f'Привет, {username}!'

Такой маршрут обрабатывает URL вида /user/ivan. Параметр username автоматически передаётся в функцию. Можно указать тип: <int:user_id> для целых чисел.

Проблема: если переменная не соответствует типу (например, строка для int), Flask вернёт 404. Следует проверять данные или использовать кастомный конвертер.

Как использовать шаблоны с циклами и условиями?

В файле шаблона (например, index.html) применяется движок Jinja2:

<!DOCTYPE html>
<html>
<head><title>{{ title }};</title></head>
<body>
  <ul>
    {% for item in items %}
      <li>{{ item }};</li>
    {% endfor %}
  </ul>
</body>
</html>

В Python передаётся список items: return render_template('index.html', items=['A','B','C']).

Ошибка: если переменная items не определена, Jinja2 выдаст UndefinedError. Проверяйте наличие переменных перед рендерингом.

Как обработать POST запрос с формой?

from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        # проверка
        return 'Успешный вход'
    return render_template('login.html')

Форма должна отправляться методом POST. Данные извлекаются из request.form.

Проблема: если поле отсутствует, возникнет KeyError. Безопаснее использовать request.form.get('username') с указанием значения по умолчанию.

Как подключить SQLAlchemy для работы с базой данных?

from flask_sqlalchemy import SQLAlchemy

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    email = db.Column(db.String(50), unique=True, nullable=False)

После определения моделей выполните db.create_all() в контексте приложения для создания таблиц.

Ошибка: RuntimeError: working outside of application context возникает при вызове db.create_all() вне запроса. Используйте with app.app_context(): db.create_all().

Как разделить приложение на модули с Blueprints?

from flask import Blueprint

auth = Blueprint('auth', __name__, url_prefix='/auth')

@auth.route('/login')
def login():
    return 'Страница входа'

# В главном файле:
app.register_blueprint(auth)

Blueprints позволяют структурировать крупные проекты. Каждый blueprint имеет своё пространство имён для маршрутов и шаблонов.

Проблема: циклические импорты между модулями. Решение - создание общего пакета app и инициализация Flask внутри функций (create_app фабрика приложений).

Как обработать ошибку 404 и показать свою страницу?

@app.errorhandler(404)
def not_found(e):
    return render_template('404.html'), 404

Создайте шаблон 404.html в папке templates. Аналогично обрабатываются 500, 403 и другие коды.

Типичная ошибка: если не вернуть второй кортеж с кодом (404), Flask может вернуть 200. Всегда указывайте код ответа.

Часто встречающиеся ошибки и их решения

  • ImportError: No module named flask - Flask не установлен. Выполните pip install flask.
  • KeyError при обращении к request.form - проверяйте метод запроса или используйте get().
  • Circular import - инициализируйте приложение через фабрику или перенесите объявление blueprints в отдельный модуль.
  • TemplateNotFound - убедитесь, что шаблон лежит в папке templates и имя написано верно.
  • RuntimeError: Working outside of application context - используйте with app.app_context(): для операций с БД или g.

Расширенные примеры с пояснениями

Генерация URL с помощью url_for

Функция url_for создаёт URL по имени функции-обработчика. Это удобно для рефакторинга маршрутов.

Пример
from flask import Flask, url_for

app = Flask(__name__)

@app.route('/profile/<int:user_id>')
def profile(user_id):
    return f'User {user_id}'

with app.test_request_context():
    print(url_for('profile', user_id=1))
    print(url_for('profile', user_id=42))
/profile/1
/profile/42

Применение: в шаблонах для ссылок, чтобы не прописывать пути жёстко. Изменение маршрута не ломает ссылки.

Использование g для хранения данных между запросами

Объект g (global) живёт только во время одного запроса. Подходит для загрузки текущего пользователя, соединения с БД и т.д.

Пример
from flask import Flask, g, session

app = Flask(__name__)
app.secret_key = 'mysecret'

@app.before_request
def load_user():
    g.user = None
    if 'user_id' in session:
        g.user = User.query.get(session['user_id'])  # гипотетическая модель

@app.route('/dashboard')
def dashboard():
    if g.user is None:
        return 'Необходима авторизация', 401
    return f'Добро пожаловать, {g.user.username}'

Важно: g не может храниться между разными запросами (в отличие от сессии). Не помещайте туда большие объекты.

При открытии /dashboard без сессии: "Необходима авторизация" с кодом 401.

Собственный декоратор для проверки прав (admin_required)

Декоратор позволяет защитить маршруты от неавторизованных пользователей, инкапсулируя логику проверки.

Пример
from functools import wraps
from flask import abort, g

def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not g.user or not g.user.is_admin:
            abort(403)
        return f(*args, **kwargs)
    return decorated_function

@app.route('/admin')
@admin_required
def admin_panel():
    return 'Административная панель'

При попытке доступа не-администратора будет возвращена страница 403 Forbidden. Можно настроить кастомный обработчик ошибок.

Для пользователя без прав: ответ с кодом 403.

Кастомный обработчик ошибок, возвращающий JSON (для API)

Если ваше приложение предоставляет REST API, удобно возвращать JSON вместо HTML при ошибках.

Пример
@app.errorhandler(404)
def not_found_json(e):
    return {'error': 'Not found', 'status': 404}, 404

@app.errorhandler(403)
def forbidden_json(e):
    return {'error': 'Forbidden', 'status': 403}, 403

Теперь при 404 или 403 возвращается JSON-объект. Не забудьте установить заголовок Content-Type: application/json (Flask делает это автоматически, если вернуть dict).

При запросе к несуществующему ресурсу:
{"error": "Not found", "status": 404}

Использование Flask-Migrate для миграций базы данных

Flask-Migrate интегрирует Alembic для управления изменениями схемы. Позволяет отслеживать изменения моделей и применять их без потери данных.

Пример
# Установка: pip install flask-migrate

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))

Команды терминала:

Пример
export FLASK_APP=app.py  # или set FLASK_APP=app.py на Windows
flask db init
flask db migrate -m "Создание таблицы User"
flask db upgrade

После изменений в моделях снова выполните flask db migrate и flask db upgrade.

В результате появляется папка migrations с историей изменений. База данных обновляется до последней версии.

Типичная ошибка: alembic.util.exc.CommandError при отсутствии переменной окружения FLASK_APP. Убедитесь, что она указывает на файл с объектом app.

Фреймворк Flask в Python - comments

En
фреймворк flask python (python)