Home » Создание веб-приложения с Flask на Python 3
Создание веб-приложения с Flask на Python 3

Создание веб-приложения с Flask на Python 3

Сейчас веб-разработка стала одним из самых востребованных направлений в IT. Каждый день появляются новые стартапы, компании переходят в онлайн, а пользователи требуют всё более сложные веб-сервисы. В этой статье мы разберем, как создать веб-приложение с Flask на Python 3 — от нуля до боевого развертывания. Если ты администратор, который хочет быстро поднять легковесный веб-сервис, или разработчик, ищущий альтернативу громоздким фреймворкам, то этот материал для тебя. Здесь будут конкретные команды, примеры кода и готовые решения для продакшена.

Что такое Flask и зачем он нужен

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

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

  • Минималистичность — весит всего несколько мегабайт
  • Гибкость — можешь подключить только нужные компоненты
  • Простота изучения — базовое приложение пишется в 5 строк
  • Активное сообщество — множество расширений и документации
  • Подходит для RESTful API и микросервисной архитектуры

Сравнение с другими фреймворками

Фреймворк Размер Кривая обучения Производительность Лучше всего для
Flask Легкий Низкая Высокая API, микросервисы
Django Тяжелый Высокая Средняя Крупные проекты
FastAPI Легкий Средняя Очень высокая Современные API
Tornado Средний Высокая Высокая Асинхронные приложения

Установка и подготовка окружения

Для работы с Flask потребуется Python 3.7+ и виртуальное окружение. Если планируешь деплоить на продакшн-сервер, рекомендую сразу арендовать VPS или выделенный сервер.

# Создание виртуального окружения
python3 -m venv flask_env
source flask_env/bin/activate  # Linux/Mac
# flask_env\Scripts\activate  # Windows

# Установка Flask
pip install Flask

# Для продакшена также понадобятся:
pip install gunicorn
pip install python-dotenv

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

Создадим простейшее Flask-приложение. Сохрани код в файл app.py:

from flask import Flask, request, jsonify
import os
from datetime import datetime

app = Flask(__name__)

# Базовый маршрут
@app.route('/')
def hello():
    return f'

Flask работает!

Текущее время: {datetime.now()}

' # API endpoint @app.route('/api/status') def api_status(): return jsonify({ 'status': 'ok', 'timestamp': datetime.now().isoformat(), 'server': os.uname().nodename if hasattr(os, 'uname') else 'unknown' }) # POST запрос @app.route('/api/echo', methods=['POST']) def echo(): data = request.get_json() if not data: return jsonify({'error': 'No JSON data provided'}), 400 return jsonify({ 'received': data, 'timestamp': datetime.now().isoformat() }) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)

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

python app.py

Приложение будет доступно по адресу http://localhost:5000. Попробуй открыть в браузере или протестировать API:

# Тестирование API
curl http://localhost:5000/api/status

# POST запрос
curl -X POST http://localhost:5000/api/echo \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello Flask!"}'

Структура проекта для продакшена

Для серьезного проекта нужна правильная структура. Создадим каталоги:

mkdir flask_project
cd flask_project

# Структура проекта
flask_project/
├── app/
│   ├── __init__.py
│   ├── routes.py
│   ├── models.py
│   └── config.py
├── templates/
├── static/
├── requirements.txt
├── .env
└── run.py

Файл app/__init__.py:

from flask import Flask
from app.config import Config

def create_app():
    app = Flask(__name__)
    app.config.from_object(Config)
    
    from app.routes import bp
    app.register_blueprint(bp)
    
    return app

Файл app/config.py:

import os
from dotenv import load_dotenv

load_dotenv()

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-change-me'
    DEBUG = os.environ.get('FLASK_DEBUG', 'False').lower() == 'true'
    HOST = os.environ.get('FLASK_HOST', '0.0.0.0')
    PORT = int(os.environ.get('FLASK_PORT', 5000))

Файл app/routes.py:

from flask import Blueprint, jsonify, request
from datetime import datetime
import psutil  # pip install psutil

bp = Blueprint('main', __name__)

@bp.route('/')
def index():
    return jsonify({'message': 'Flask API v1.0', 'timestamp': datetime.now().isoformat()})

@bp.route('/health')
def health_check():
    return jsonify({
        'status': 'healthy',
        'uptime': datetime.now().isoformat(),
        'memory_usage': psutil.virtual_memory().percent,
        'cpu_usage': psutil.cpu_percent()
    })

@bp.route('/api/v1/data', methods=['GET', 'POST'])
def handle_data():
    if request.method == 'GET':
        return jsonify({'data': 'Sample data', 'method': 'GET'})
    elif request.method == 'POST':
        json_data = request.get_json()
        return jsonify({'received': json_data, 'method': 'POST'})

Файл run.py:

from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run(
        debug=app.config['DEBUG'],
        host=app.config['HOST'],
        port=app.config['PORT']
    )

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

Создай файл .env:

SECRET_KEY=your-super-secret-key-here
FLASK_DEBUG=false
FLASK_HOST=0.0.0.0
FLASK_PORT=5000

Файл requirements.txt:

Flask==2.3.3
python-dotenv==1.0.0
gunicorn==21.2.0
psutil==5.9.5

Развертывание с Gunicorn

Для продакшена Flask нужно запускать через WSGI-сервер. Gunicorn — отличный выбор:

# Базовый запуск
gunicorn -w 4 -b 0.0.0.0:5000 run:app

# Продвинутая конфигурация
gunicorn -w 4 -b 0.0.0.0:5000 \
  --access-logfile /var/log/flask/access.log \
  --error-logfile /var/log/flask/error.log \
  --log-level info \
  --timeout 120 \
  --keep-alive 5 \
  --max-requests 1000 \
  --max-requests-jitter 100 \
  run:app

Создай systemd-сервис для автозапуска. Файл /etc/systemd/system/flask-app.service:

[Unit]
Description=Flask App
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/flask_project
Environment=PATH=/var/www/flask_project/flask_env/bin
ExecStart=/var/www/flask_project/flask_env/bin/gunicorn -w 4 -b 0.0.0.0:5000 run:app
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target

Активация сервиса:

sudo systemctl daemon-reload
sudo systemctl enable flask-app
sudo systemctl start flask-app
sudo systemctl status flask-app

Настройка Nginx как reverse proxy

Конфигурация Nginx для Flask-приложения. Файл /etc/nginx/sites-available/flask-app:

server {
    listen 80;
    server_name your-domain.com;
    
    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }
    
    location /static/ {
        root /var/www/flask_project;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
    
    # Для API можно добавить CORS
    location /api/ {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # CORS headers
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
        add_header Access-Control-Allow-Headers "Authorization, Content-Type";
        
        if ($request_method = OPTIONS) {
            return 204;
        }
    }
}

Активация конфигурации:

sudo ln -s /etc/nginx/sites-available/flask-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Мониторинг и логирование

Добавим систему логирования в Flask-приложение. Обнови app/__init__.py:

import logging
from logging.handlers import RotatingFileHandler
from flask import Flask
from app.config import Config

def create_app():
    app = Flask(__name__)
    app.config.from_object(Config)
    
    # Настройка логирования
    if not app.debug:
        if not os.path.exists('logs'):
            os.mkdir('logs')
        
        file_handler = RotatingFileHandler('logs/flask_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 application startup')
    
    from app.routes import bp
    app.register_blueprint(bp)
    
    return app

Скрипт для мониторинга состояния приложения:

#!/bin/bash
# monitoring.sh

check_app() {
    response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000/health)
    if [ "$response" = "200" ]; then
        echo "$(date): App is healthy"
    else
        echo "$(date): App is down (HTTP $response)"
        # Перезапуск сервиса
        sudo systemctl restart flask-app
    fi
}

# Добавь в crontab: */5 * * * * /path/to/monitoring.sh
check_app

Интеграция с базой данных

Для работы с БД используем SQLAlchemy. Добавь в requirements.txt:

Flask-SQLAlchemy==3.0.5
Flask-Migrate==4.0.5

Обнови app/models.py:

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

db = SQLAlchemy()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    def to_dict(self):
        return {
            'id': self.id,
            'username': self.username,
            'email': self.email,
            'created_at': self.created_at.isoformat()
        }

class ApiLog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    endpoint = db.Column(db.String(255), nullable=False)
    method = db.Column(db.String(10), nullable=False)
    ip_address = db.Column(db.String(45), nullable=False)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)
    response_code = db.Column(db.Integer)

Обнови app/config.py:

import os
from dotenv import load_dotenv

load_dotenv()

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-change-me'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    DEBUG = os.environ.get('FLASK_DEBUG', 'False').lower() == 'true'
    HOST = os.environ.get('FLASK_HOST', '0.0.0.0')
    PORT = int(os.environ.get('FLASK_PORT', 5000))

Расширенный API с аутентификацией

Добавим JWT-аутентификацию:

pip install Flask-JWT-Extended

Обнови app/routes.py:

from flask import Blueprint, jsonify, request
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
from datetime import datetime, timedelta
from app.models import db, User, ApiLog
import hashlib

bp = Blueprint('main', __name__)

@bp.route('/auth/login', methods=['POST'])
def login():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')
    
    if not username or not password:
        return jsonify({'error': 'Username and password required'}), 400
    
    # Простая проверка (в реальном проекте используй proper hashing)
    user = User.query.filter_by(username=username).first()
    if user:
        access_token = create_access_token(
            identity=user.id,
            expires_delta=timedelta(hours=24)
        )
        return jsonify({
            'access_token': access_token,
            'user': user.to_dict()
        })
    
    return jsonify({'error': 'Invalid credentials'}), 401

@bp.route('/auth/register', methods=['POST'])
def register():
    data = request.get_json()
    username = data.get('username')
    email = data.get('email')
    
    if User.query.filter_by(username=username).first():
        return jsonify({'error': 'Username already exists'}), 400
    
    user = User(username=username, email=email)
    db.session.add(user)
    db.session.commit()
    
    return jsonify({'message': 'User created', 'user': user.to_dict()}), 201

@bp.route('/protected', methods=['GET'])
@jwt_required()
def protected():
    current_user_id = get_jwt_identity()
    user = User.query.get(current_user_id)
    
    return jsonify({
        'message': 'This is a protected endpoint',
        'user': user.to_dict() if user else None
    })

Полезные расширения для Flask

Список популярных расширений, которые стоит изучить:

  • Flask-CORS — для работы с Cross-Origin Resource Sharing
  • Flask-Limiter — ограничение частоты запросов
  • Flask-Caching — кеширование ответов
  • Flask-Mail — отправка email
  • Flask-Admin — админка для модели данных
  • Flask-SocketIO — WebSocket поддержка
  • Flask-RESTful — для создания REST API
  • Celery — асинхронные задачи

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

from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["200 per day", "50 per hour"]
)

@bp.route('/api/limited')
@limiter.limit("10 per minute")
def limited_endpoint():
    return jsonify({'message': 'Rate limited endpoint'})

Автоматизация и CI/CD

Скрипт для автоматического деплоя:

#!/bin/bash
# deploy.sh

set -e

echo "Starting deployment..."

# Переход в директорию проекта
cd /var/www/flask_project

# Обновление кода
git pull origin main

# Активация виртуального окружения
source flask_env/bin/activate

# Установка зависимостей
pip install -r requirements.txt

# Миграции базы данных
flask db upgrade

# Перезапуск сервиса
sudo systemctl restart flask-app

# Проверка статуса
sleep 5
if curl -f http://localhost:5000/health > /dev/null; then
    echo "Deployment successful!"
else
    echo "Deployment failed!"
    exit 1
fi

Пример GitHub Actions workflow (.github/workflows/deploy.yml):

name: Deploy Flask App

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.9'
    
    - name: Install dependencies
      run: |
        pip install -r requirements.txt
        pip install pytest
    
    - name: Run tests
      run: pytest tests/
    
    - name: Deploy to server
      uses: appleboy/ssh-action@v0.1.5
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.SSH_KEY }}
        script: |
          cd /var/www/flask_project
          ./deploy.sh

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

Создай файл tests/test_app.py:

import pytest
from app import create_app
from app.models import db, User

@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_health_check(client):
    response = client.get('/health')
    assert response.status_code == 200
    data = response.get_json()
    assert data['status'] == 'healthy'

def test_user_registration(client):
    response = client.post('/auth/register', json={
        'username': 'testuser',
        'email': 'test@example.com'
    })
    assert response.status_code == 201
    data = response.get_json()
    assert data['user']['username'] == 'testuser'

def test_protected_endpoint_without_token(client):
    response = client.get('/protected')
    assert response.status_code == 401

Запуск тестов:

pip install pytest
pytest tests/ -v

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

Несколько советов для повышения производительности Flask-приложения:

  • Используй Redis для кеширования — Flask-Caching с Redis backend
  • Оптимизируй запросы к БД — используй индексы и избегай N+1 проблем
  • Настрой правильно Gunicorn — количество воркеров = (CPU cores * 2) + 1
  • Используй CDN для статики — AWS CloudFront или Cloudflare
  • Мониторинг — подключи Prometheus + Grafana

Пример конфигурации Redis cache:

from flask_caching import Cache

cache = Cache(app, config={
    'CACHE_TYPE': 'redis',
    'CACHE_REDIS_URL': 'redis://localhost:6379/0',
    'CACHE_DEFAULT_TIMEOUT': 300
})

@bp.route('/api/cached-data')
@cache.cached(timeout=60)
def cached_endpoint():
    # Дорогая операция
    return jsonify({'data': 'This response is cached'})

Безопасность Flask-приложения

Обязательные меры безопасности:

  • Используй HTTPS — настрой SSL через Let’s Encrypt
  • Валидируй входные данные — используй Flask-WTF или marshmallow
  • Настрой CORS правильно — не используй wildcards в продакшене
  • Скрой информацию о сервере — отключи debug в продакшене
  • Используй helmet для заголовков безопасности

Пример middleware для безопасности:

from flask import Flask
from flask_talisman import Talisman

app = Flask(__name__)
Talisman(app, force_https=True)

@app.after_request
def security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    return response

Интересные применения Flask

Flask отлично подходит для нестандартных задач:

  • Webhook обработчики — для GitHub, GitLab, Stripe
  • Микросервисы — небольшие специализированные сервисы
  • API Gateway — прокси для других сервисов
  • Админские панели — с Flask-Admin
  • Интеграция с IoT — прием данных с датчиков
  • Chatbot API — обработка сообщений от Telegram, Discord

Пример webhook обработчика:

import hmac
import hashlib

@bp.route('/webhook/github', methods=['POST'])
def github_webhook():
    signature = request.headers.get('X-Hub-Signature-256')
    if not verify_signature(request.data, signature):
        return jsonify({'error': 'Invalid signature'}), 401
    
    payload = request.get_json()
    if payload.get('action') == 'opened':
        # Обработка нового PR
        handle_new_pr(payload)
    
    return jsonify({'status': 'processed'})

def verify_signature(payload, signature):
    secret = os.environ.get('GITHUB_WEBHOOK_SECRET')
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(f'sha256={expected}', signature)

Полезные ресурсы

Официальная документация и полезные ссылки:

Заключение и рекомендации

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

  • Быстрый старт — можешь создать рабочий API за 10 минут
  • Масштабируемость — легко добавлять новые компоненты
  • Производительность — при правильной настройке показывает отличные результаты
  • Сообщество — множество расширений и готовых решений

Рекомендую использовать Flask для:

  • REST API и микросервисов
  • Прототипов и MVP
  • Интеграционных сервисов
  • Админских панелей
  • Webhook обработчиков

Для крупных проектов с множеством форм и сложной логикой лучше рассмотреть Django. Если нужна максимальная производительность для API — обрати внимание на FastAPI.

Помни про безопасность, мониторинг и правильное конфигурирование продакшен-окружения. Удачи в разработке!


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

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

Leave a reply

Your email address will not be published. Required fields are marked