Flask – лёгкий веб-фреймворк

онлайн тренажер по питону
Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Flask - полное руководство по веб-фреймворку Python

Введение в Flask

Flask — это минималистичный веб-фреймворк на Python, предназначенный для создания веб-приложений и REST API. Он предоставляет простую и гибкую структуру, позволяющую быстро разработать как прототип, так и полнофункциональное веб-приложение. Flask основан на WSGI-инструментарии Werkzeug и использует систему шаблонов Jinja2.

Созданный Армином Ронахером в 2010 году, Flask завоевал популярность благодаря философии "делай одно, но делай хорошо". В отличие от более тяжеловесных фреймворков, Flask предоставляет только необходимый минимум, позволяя разработчикам самостоятельно выбирать компоненты для своих проектов.

Основные особенности Flask

Минималистичный и расширяемый подход

Flask следует принципу микрофреймворка, предоставляя базовый функционал и позволяя расширять его через плагины и расширения.

Встроенная маршрутизация и обработка запросов

Фреймворк предоставляет интуитивно понятную систему маршрутизации с поддержкой различных HTTP-методов и параметров URL.

Поддержка шаблонов Jinja2

Интеграция с мощной системой шаблонов Jinja2 обеспечивает удобную работу с HTML-шаблонами и динамическим контентом.

Возможность создания REST API

Flask отлично подходит для создания RESTful API благодаря поддержке JSON-ответов и гибкой обработке HTTP-методов.

Поддержка расширений

Богатая экосистема расширений позволяет добавить функциональность для работы с базами данных, аутентификацией, формами и многим другим.

Совместимость с Python 3.7+

Flask поддерживает современные версии Python и следует лучшим практикам разработки.

Установка и настройка

Установка через pip

pip install flask

Проверка установки

python -m flask --version

Создание файла app.py и запуск

export FLASK_APP=app.py
flask run

Для Windows:

set FLASK_APP=app.py
flask run

Создание первого приложения

Простой пример app.py

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "Добро пожаловать во Flask!"

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

Запуск приложения

flask run

Приложение будет доступно по адресу http://localhost:5000/

Обработка маршрутов и URL

Базовая маршрутизация

@app.route("/user/<username>")
def show_user_profile(username):
    return f"Профиль пользователя: {username}"

Маршруты с типизацией

@app.route("/post/<int:post_id>")
def show_post(post_id):
    return f"Пост №{post_id}"

@app.route("/user/<path:subpath>")
def show_subpath(subpath):
    return f"Подпуть: {subpath}"

Поддерживаемые типы параметров

  • string - строки (по умолчанию)
  • int - целые числа
  • float - числа с плавающей точкой
  • path - строки с символами "/"
  • uuid - UUID-строки

Работа с HTTP-методами

Обработка различных методов

@app.route("/data", methods=["GET", "POST", "PUT", "DELETE"])
def handle_data():
    if request.method == "POST":
        return "Данные созданы"
    elif request.method == "PUT":
        return "Данные обновлены"
    elif request.method == "DELETE":
        return "Данные удалены"
    return "Получение данных"

Работа с шаблонами Jinja2

Создание шаблонов

Создайте папку templates и файл index.html:

<!-- templates/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>Привет, {{ name }}!</h1>
    <p>Сегодня {{ date.strftime('%d.%m.%Y') }}</p>
</body>
</html>

Использование в приложении

from flask import render_template
from datetime import datetime

@app.route("/hello/<name>")
def hello(name):
    return render_template("index.html", 
                         name=name, 
                         title="Приветствие",
                         date=datetime.now())

Наследование шаблонов

Базовый шаблон base.html:

<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Мой сайт{% endblock %}</title>
</head>
<body>
    <nav>
        <ul>
            <li><a href="/">Главная</a></li>
            <li><a href="/about">О нас</a></li>
        </ul>
    </nav>
    
    <main>
        {% block content %}{% endblock %}
    </main>
</body>
</html>

Дочерний шаблон:

<!-- templates/home.html -->
{% extends "base.html" %}

{% block title %}Главная - Мой сайт{% endblock %}

{% block content %}
<h1>Добро пожаловать!</h1>
<p>Это главная страница сайта.</p>
{% endblock %}

Обработка форм и методов POST/GET

Простая форма

from flask import request

@app.route("/form", methods=["GET", "POST"])
def form():
    if request.method == "POST":
        username = request.form["username"]
        email = request.form["email"]
        return f"Привет, {username}! Email: {email}"
    
    return '''
    <form method="post">
        <input name="username" placeholder="Имя" required>
        <input name="email" type="email" placeholder="Email" required>
        <input type="submit" value="Отправить">
    </form>
    '''

Обработка файлов

from werkzeug.utils import secure_filename
import os

@app.route("/upload", methods=["GET", "POST"])
def upload_file():
    if request.method == "POST":
        if 'file' not in request.files:
            return "Файл не выбран"
        
        file = request.files['file']
        if file.filename == '':
            return "Файл не выбран"
        
        if file:
            filename = secure_filename(file.filename)
            file.save(os.path.join('uploads', filename))
            return f"Файл {filename} успешно загружен"
    
    return '''
    <form method="post" enctype="multipart/form-data">
        <input type="file" name="file">
        <input type="submit" value="Загрузить">
    </form>
    '''

Работа с базами данных

Использование SQLAlchemy

pip install flask-sqlalchemy
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

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(120), unique=True, nullable=False)
    password_hash = db.Column(db.String(60), nullable=False)
    posts = db.relationship('Post', backref='author', lazy=True)
    
    def __repr__(self):
        return f"User('{self.username}', '{self.email}')"

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    
    def __repr__(self):
        return f"Post('{self.title}', '{self.date_posted}')"

Создание базы данных

@app.before_first_request
def create_tables():
    db.create_all()

Создание REST API с Flask

Базовый API

from flask import jsonify, request

@app.route("/api/users", methods=["GET"])
def get_users():
    users = User.query.all()
    return jsonify([{
        'id': user.id,
        'username': user.username,
        'email': user.email
    } for user in users])

@app.route("/api/users", methods=["POST"])
def create_user():
    data = request.get_json()
    
    if not data or 'username' not in data or 'email' not in data:
        return jsonify({'error': 'Недостаточно данных'}), 400
    
    user = User(
        username=data['username'],
        email=data['email'],
        password_hash='hashed_password'  # В реальном приложении используйте хеширование
    )
    
    db.session.add(user)
    db.session.commit()
    
    return jsonify({
        'message': 'Пользователь создан',
        'user': {
            'id': user.id,
            'username': user.username,
            'email': user.email
        }
    }), 201

Использование Flask-RESTful

pip install flask-restful
from flask_restful import Api, Resource

api = Api(app)

class UserListAPI(Resource):
    def get(self):
        users = User.query.all()
        return [{'id': u.id, 'username': u.username} for u in users]
    
    def post(self):
        data = request.get_json()
        user = User(username=data['username'], email=data['email'])
        db.session.add(user)
        db.session.commit()
        return {'message': 'Пользователь создан'}, 201

api.add_resource(UserListAPI, '/api/users')

Работа с сессиями и куки

Настройка сессий

from flask import session

app.secret_key = 'your-secret-key-here'  # В продакшене используйте os.urandom(24)

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]
        
        # Проверка пользователя (упрощенная версия)
        user = User.query.filter_by(username=username).first()
        if user and check_password_hash(user.password_hash, password):
            session["user_id"] = user.id
            session["username"] = user.username
            return redirect(url_for("dashboard"))
        else:
            return "Неверные данные для входа"
    
    return '''
    <form method="post">
        <input name="username" placeholder="Имя пользователя" required>
        <input name="password" type="password" placeholder="Пароль" required>
        <input type="submit" value="Войти">
    </form>
    '''

@app.route("/logout")
def logout():
    session.pop("user_id", None)
    session.pop("username", None)
    return redirect(url_for("home"))

Работа с куки

from flask import make_response

@app.route("/set_cookie")
def set_cookie():
    response = make_response("Куки установлены")
    response.set_cookie("username", "john_doe", max_age=60*60*24)  # 24 часа
    return response

@app.route("/get_cookie")
def get_cookie():
    username = request.cookies.get("username", "Гость")
    return f"Привет, {username}!"

Обработка ошибок и логирование

Обработка ошибок

@app.errorhandler(404)
def page_not_found(error):
    return render_template("404.html"), 404

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

@app.errorhandler(403)
def forbidden(error):
    return render_template("403.html"), 403

Настройка логирования

import logging
from logging.handlers import RotatingFileHandler

if not app.debug:
    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 приложение запущено')

Подключение расширений Flask

Популярные расширения

Flask-WTF — формы и CSRF-защита:

pip install flask-wtf

Flask-Login — система аутентификации:

pip install flask-login

Flask-Migrate — миграции базы данных:

pip install flask-migrate

Flask-Mail — отправка электронной почты:

pip install flask-mail

Пример использования Flask-WTF

from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Email, Length

class ContactForm(FlaskForm):
    name = StringField('Имя', validators=[DataRequired(), Length(min=2, max=50)])
    email = StringField('Email', validators=[DataRequired(), Email()])
    message = TextAreaField('Сообщение', validators=[DataRequired(), Length(min=10)])
    submit = SubmitField('Отправить')

@app.route("/contact", methods=["GET", "POST"])
def contact():
    form = ContactForm()
    if form.validate_on_submit():
        # Обработка формы
        return redirect(url_for("thank_you"))
    return render_template("contact.html", form=form)

Организация структуры крупного проекта

Рекомендуемая структура

project/
├── app/
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   ├── forms.py
│   └── utils.py
├── templates/
│   ├── base.html
│   ├── index.html
│   └── errors/
│       ├── 404.html
│       └── 500.html
├── static/
│   ├── css/
│   ├── js/
│   └── images/
├── migrations/
├── tests/
├── config.py
├── requirements.txt
└── run.py

Использование Blueprint

# app/main.py
from flask import Blueprint

main = Blueprint('main', __name__)

@main.route('/')
def index():
    return render_template('index.html')

@main.route('/about')
def about():
    return render_template('about.html')
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    app.config.from_object('config')
    
    db.init_app(app)
    
    from app.main import main as main_blueprint
    app.register_blueprint(main_blueprint)
    
    return app

Тестирование Flask-приложений

Базовые тесты

import pytest
from app import create_app, db

@pytest.fixture
def app():
    app = create_app()
    app.config['TESTING'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
    
    with app.app_context():
        db.create_all()
        yield app
        db.drop_all()

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

def test_home_page(client):
    response = client.get('/')
    assert response.status_code == 200
    assert b'Добро пожаловать' in response.data

def test_login_post(client):
    response = client.post('/login', data={
        'username': 'testuser',
        'password': 'testpass'
    })
    assert response.status_code == 302  # Редирект после успешного входа

Тестирование API

def test_api_users_get(client):
    response = client.get('/api/users')
    assert response.status_code == 200
    assert response.content_type == 'application/json'

def test_api_users_post(client):
    response = client.post('/api/users', json={
        'username': 'newuser',
        'email': 'newuser@example.com'
    })
    assert response.status_code == 201
    data = response.get_json()
    assert data['message'] == 'Пользователь создан'

Развёртывание Flask-приложений

Использование Gunicorn

pip install gunicorn
gunicorn -w 4 -b 127.0.0.1:8000 app:app

Docker-контейнер

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]

Конфигурация для продакшена

# config.py
import os

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False

config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}

Таблица основных методов и функций Flask

Компонент Описание Пример использования
Flask(__name__) Создает экземпляр Flask-приложения app = Flask(__name__)
@app.route() Декоратор для маршрутизации @app.route('/users')
render_template() Отрисовка HTML-шаблона render_template('index.html', data=data)
request.method HTTP-метод запроса if request.method == 'POST':
request.form Данные из HTML-формы username = request.form['username']
request.args Параметры из URL page = request.args.get('page', 1)
request.json JSON-данные запроса data = request.json
request.files Загруженные файлы file = request.files['upload']
jsonify() Создание JSON-ответа return jsonify({'status': 'success'})
redirect() HTTP-редирект return redirect(url_for('home'))
url_for() Генерация URL по имени функции url_for('user_profile', id=1)
session Работа с сессиями session['user_id'] = user.id
make_response() Создание объекта ответа resp = make_response('Hello')
abort() Возбуждение HTTP-ошибки abort(404)
flash() Сообщения для пользователя flash('Успешно сохранено')
get_flashed_messages() Получение сообщений messages = get_flashed_messages()
@app.before_request Выполнение перед каждым запросом @app.before_request
@app.after_request Выполнение после каждого запроса @app.after_request
@app.errorhandler() Обработка ошибок @app.errorhandler(404)
Blueprint() Создание модуля приложения bp = Blueprint('main', __name__)
app.register_blueprint() Регистрация Blueprint app.register_blueprint(bp)
current_app Контекст текущего приложения current_app.config['DEBUG']
g Глобальный объект контекста g.user = current_user

Примеры практического применения Flask

Создание API для мобильных приложений

Flask отлично подходит для создания RESTful API, которые могут обслуживать мобильные приложения. Благодаря легковесности и гибкости, он позволяет быстро создавать и масштабировать API-сервисы.

Панели администратора и CRM-системы

Используя Flask совместно с расширениями Flask-Admin и Flask-Login, можно создавать мощные административные панели и CRM-системы.

Бэкенды для чат-ботов и Telegram-ботов

Flask может служить webhook-сервером для обработки сообщений от различных мессенджеров и социальных сетей.

Мониторинг и аналитика в реальном времени

Благодаря поддержке WebSocket (через Flask-SocketIO) можно создавать системы мониторинга с обновлением данных в реальном времени.

Прототипирование ML/AI моделей

Flask позволяет быстро создавать веб-интерфейсы для машинного обучения и искусственного интеллекта, делая модели доступными через REST API.

Безопасность во Flask

Защита от CSRF-атак

from flask_wtf.csrf import CSRFProtect

csrf = CSRFProtect(app)

Хеширование паролей

from werkzeug.security import generate_password_hash, check_password_hash

password_hash = generate_password_hash('user_password')
is_valid = check_password_hash(password_hash, 'user_password')

Валидация данных

from wtforms.validators import DataRequired, Length, Email, ValidationError

def validate_username(self, username):
    user = User.query.filter_by(username=username.data).first()
    if user:
        raise ValidationError('Имя пользователя уже занято')

Оптимизация производительности

Кеширование

from flask_caching import Cache

cache = Cache(app)

@app.route('/expensive_operation')
@cache.cached(timeout=300)  # 5 минут
def expensive_operation():
    # Долгая операция
    return result

Пагинация

@app.route('/posts')
def posts():
    page = request.args.get('page', 1, type=int)
    posts = Post.query.paginate(
        page=page,
        per_page=10,
        error_out=False
    )
    return render_template('posts.html', posts=posts)

Часто задаваемые вопросы

Что такое Flask и для чего он используется?

Flask — это легковесный веб-фреймворк на Python для создания веб-приложений, REST API и веб-сервисов. Он отлично подходит для прототипирования, создания микросервисов и разработки как небольших, так и крупных веб-приложений.

Поддерживает ли Flask работу с базами данных?

Да, Flask поддерживает работу с различными базами данных через расширения. Наиболее популярное — Flask-SQLAlchemy, которое обеспечивает интеграцию с SQLAlchemy ORM и поддерживает SQLite, PostgreSQL, MySQL и другие базы данных.

Является ли Flask асинхронным фреймворком?

Flask поддерживает асинхронные функции начиная с версии 2.0, но не является полностью асинхронным фреймворком. Для полноценной асинхронной разработки рекомендуется использовать FastAPI или Quart.

Можно ли использовать Flask для крупных проектов?

Да, Flask можно использовать для крупных проектов при правильной архитектуре. Ключевые принципы: использование Blueprint для модульности, правильная организация кода, применение паттернов проектирования и использование соответствующих расширений.

Чем Flask отличается от Django?

Flask — это микрофреймворк с минимальной структурой, предоставляющий только основные компоненты. Django — это полнофункциональный фреймворк с множеством встроенных компонентов (ORM, админка, система аутентификации). Flask более гибкий, Django более функциональный из коробки.

Как обеспечить безопасность Flask-приложения?

Основные меры безопасности: использование CSRF-защиты, хеширование паролей, валидация пользовательского ввода, использование HTTPS, настройка правильных заголовков безопасности, регулярное обновление зависимостей.

Какие расширения Flask наиболее полезны?

Наиболее полезные расширения: Flask-SQLAlchemy (база данных), Flask-Login (аутентификация), Flask-WTF (формы), Flask-Migrate (миграции), Flask-Mail (почта), Flask-CORS (CORS), Flask-Caching (кеширование).

Как развернуть Flask-приложение в продакшене?

Для продакшена рекомендуется использовать WSGI-сервер (Gunicorn, uWSGI) за обратным прокси (Nginx). Также можно использовать контейнеризацию (Docker) и облачные платформы (Heroku, AWS, Google Cloud).

Заключение

Flask — это мощный и гибкий инструмент для разработки веб-приложений на Python. Его философия минимализма и расширяемости делает его идеальным выбором для широкого спектра задач — от простых прототипов до сложных корпоративных систем.

Основные преимущества Flask:

  • Простота изучения и использования
  • Гибкость и расширяемость
  • Богатая экосистема расширений
  • Активное сообщество разработчиков
  • Отличная документация
  • Совместимость с современными технологиями

Благодаря этим качествам Flask остается одним из самых популярных веб-фреймворков Python и продолжает развиваться, адаптируясь к современным требованиям веб-разработки. Независимо от того, являетесь ли вы начинающим разработчиком или опытным профессионалом, Flask предоставляет все необходимые инструменты для создания качественных веб-приложений.

Новости