Интеграция двух фреймворков: FastAPI внутри Django и наоборот

Раздел: Взаимодействие с внешними сервисами -> Интеграция с фреймворками

Варианты интеграции FastAPI и Django

При совместном использовании FastAPI и Django возникает потребность объединить их возможности: асинхронность FastAPI и экосистему Django (ORM, админка, аутентификация). Рассмотрены несколько подходов, от самого эффективного до альтернативных сценариев.

Как использовать модели Django внутри FastAPI без полного запуска Django?

Наиболее эффективный способ - инициализировать Django прямо в коде FastAPI, настроить подключение к базе данных и вызывать ORM синхронно через sync_to_async. Этот подход позволяет сохранить все преимущества Django (миграции, админку) и при этом получить быстрые асинхронные эндпоинты FastAPI.


# settings.py (Django) - стандартный
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydb',
        'USER': 'user',
        'PASSWORD': 'pass',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

# models.py (Django)
from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

Fastapi django python (интеграция fastapi с django)


# fastapi_app.py
import os
import django
from fastapi import FastAPI, HTTPException
from asgiref.sync import sync_to_async

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()

from myapp.models import Product

app = FastAPI()

@sync_to_async
def get_product_list():
    return list(Product.objects.all().values('id', 'name', 'price'))

@app.get("/products")
async def list_products():
    products = await get_product_list()
    return {"products": products}

Пояснение шагов:

  • Устанавливается переменная окружения DJANGO_SETTINGS_MODULE и вызывается django.setup() до импорта моделей.
  • Функции, работающие с Django ORM, оборачиваются декоратором @sync_to_async для асинхронного вызова.
  • FastAPI обрабатывает запросы асинхронно, а вызовы к базе выполняются в отдельном потоке.
Проблемы и их решения:
  • Ошибка "django.core.exceptions.AppRegistryNotReady" - возникает, если django.setup() не вызван или вызван после импорта моделей. Решение: установить DJANGO_SETTINGS_MODULE и вызвать setup в самом начале файла FastAPI.
  • Многопоточность и сессии - при большом количестве запросов потоки могут блокироваться. Рекомендуется использовать пул соединений (через CONN_MAX_AGE в настройках Django) и асинхронные драйверы БД, если доступны.

Как запустить FastAPI и Django как отдельные сервисы с общей базой данных?

Если требуется полная изоляция процессов, можно развернуть два приложения: Django на порту 8000 (через gunicorn) и FastAPI на порту 8001 (через uvicorn). Общая база данных (PostgreSQL, MySQL) используется через одинаковые настройки в обоих проектах. Для обмена данными FastAPI может вызывать внутреннее API Django или напрямую обращаться к БД (если модели синхронизированы).


# Запуск Django через gunicorn (синхронный)
gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 --workers 4

# Запуск FastAPI через uvicorn
uvicorn main:app --host 0.0.0.0 --port 8001 --workers 2
Проблемы:
  • Дублирование конфигурации - настройки БД и моделей приходится копировать. Решение: вынести общий код (модели, миграции) в отдельный пакет, устанавливаемый в оба проекта.
  • Синхронизация миграций - миграции применяются только из Django. FastAPI должен использовать ту же версию схемы.

Как объединить FastAPI и Django в одном ASGI-приложении с помощью Starlette middleware?

Можно создать единое ASGI-приложение, которое маршрутизирует запросы между Django (WSGI) и FastAPI (ASGI) на основе пути. Для этого используется Starlette.middleware.wsgi.WSGIMiddleware или кастомное middleware.


# combine.py
from fastapi import FastAPI
from starlette.middleware.wsgi import WSGIMiddleware
from django.core.wsgi import get_wsgi_application
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django_app = get_wsgi_application()

app = FastAPI()

@app.get("/api/hello")
async def hello():
    return {"message": "FastAPI"}

app.mount("/django", WSGIMiddleware(django_app))

# Теперь все запросы к /django/* идут в Django, остальные в FastAPI
Проблемы:
  • Конфликт middleware и аутентификации - сессии Django и JWT FastAPI могут не согласовываться. Решение: использовать единую куку или токен, либо проксировать аутентификацию через FastAPI.
  • Различные способы обработки статики - статические файлы Django требуют отдельной настройки в ASGI.

Как обновлять модели Django из FastAPI без запуска Django?

Если требуется только читать данные, можно использовать библиотеку dj-database-url и прямые SQL-запросы через asyncpg. Но при записи лучше использовать официальный подход с Django ORM через sync_to_async. Альтернатива - использовать SQLAlchemy с async драйвером, синхронизируя схемы с Django миграциями.


# Использование async SQLAlchemy с общей базой
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "postgresql+asyncpg://user:pass@localhost/mydb"
engine = create_async_engine(DATABASE_URL)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

async def get_db():
    async with async_session() as session:
        yield session
Проблемы:
  • Дублирование ORM-логики - необходимо поддерживать и Django ORM, и SQLAlchemy. Решение: генерировать SQLAlchemy модели из Django схемы с помощью sqlacodegen.

Расширенные примеры интеграции с кодом и результатами

Ниже приведены полные сценарии: от настройки Django ORM в FastAPI до совместной аутентификации.

Пример 1. Полноценное приложение FastAPI с моделями Django и миграциями

Пример

# 1. Структура проекта
myproject/
├── myproject/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── myapp/
│   ├── __init__.py
│   ├── models.py
│   ├── admin.py
│   └── migrations/
├── fastapi_app/
│   ├── __init__.py
│   ├── main.py
│   └── dependencies.py
├── manage.py
└── requirements.txt

# 2. settings.py - настройки БД и установка приложения
INSTALLED_APPS = [
    'django.contrib.contenttypes',
    'django.contrib.auth',
    'myapp',
]
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'integrated_db',
        'USER': 'admin',
        'PASSWORD': 'secret',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

# 3. models.py (Django) - модель с пользовательскими полями
from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    published = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'articles'

# 4. Миграции
# python manage.py makemigrations myapp
# python manage.py migrate

# 5. fastapi_app/main.py - FastAPI с Django ORM
import os
import django
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from asgiref.sync import sync_to_async
from datetime import datetime

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()

from myapp.models import Article

app = FastAPI(title='Articles API')

class ArticleIn(BaseModel):
    title: str
    content: str
    published: bool = False

class ArticleOut(BaseModel):
    id: int
    title: str
    content: str
    published: bool
    created_at: datetime

@sync_to_async
def create_article(data):
    article = Article.objects.create(
        title=data.title,
        content=data.content,
        published=data.published
    )
    return article

@sync_to_async
def list_articles():
    return list(Article.objects.all().values('id', 'title', 'content', 'published', 'created_at'))

@app.post("/articles", response_model=ArticleOut)
async def add_article(article: ArticleIn):
    obj = await create_article(article)
    return ArticleOut(
        id=obj.id,
        title=obj.title,
        content=obj.content,
        published=obj.published,
        created_at=obj.created_at
    )

@app.get("/articles")
async def get_articles():
    items = await list_articles()
    return items
# Результат запроса POST /articles
# Body: { "title": "Test", "content": "Some text", "published": true }
# Ответ:
{
  "id": 1,
  "title": "Test",
  "content": "Some text",
  "published": true,
  "created_at": "2025-03-25T10:00:00Z"
}

# GET /articles
[
  {
    "id": 1,
    "title": "Test",
    "content": "Some text",
    "published": true,
    "created_at": "2025-03-25T10:00:00Z"
  }
]

Пример 2. Использование Django аутентификации в FastAPI (сессии или JWT)

При запуске Django ORM внутри FastAPI можно использовать встроенную систему аутентификации. Например, проверять пользователя по сессионной куке или по токену из заголовка.

Пример

# dependencies.py
from fastapi import Header, HTTPException
from asgiref.sync import sync_to_async
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser

User = get_user_model()

@sync_to_async
def get_user_by_token(token: str):
    # Пример: ищем пользователя по токену в модели Token (django-rest-framework)
    from rest_framework.authtoken.models import Token
    try:
        token_obj = Token.objects.get(key=token)
        return token_obj.user
    except Token.DoesNotExist:
        return AnonymousUser()

async def get_current_user(authorization: str = Header(None)):
    if not authorization or not authorization.startswith('Token '):
        raise HTTPException(status_code=401, detail="Missing or invalid token")
    token = authorization.split(' ')[1]
    user = await get_user_by_token(token)
    if user.is_anonymous:
        raise HTTPException(status_code=401, detail="Invalid token")
    return user
Пример

# main.py - защищенный эндпоинт
from fastapi import Depends
from .dependencies import get_current_user

@app.get("/me")
async def read_current_user(user: User = Depends(get_current_user)):
    return {
        "id": user.id,
        "username": user.username,
        "email": user.email
    }

Пример 3. Совместная миграция данных при общих моделях

Если используется подход с двумя отдельными приложениями (Django и FastAPI) и общей базой, то для применения миграций достаточно запускать python manage.py migrate в проекте Django. FastAPI при этом должен работать с той же схемой. Рекомендуется использовать общий пакет с моделями, установленный через pip.

Пример

# shared_models/
#   __init__.py
#   models.py (содержит те же классы, что и в Django)
#   setups.py (функция инициализации Django settings)

# В проекте FastAPI:
from shared_models.setups import init_django
init_django()  # вызывает django.setup()
from shared_models.models import Product

Интеграция FastAPI с Django - comments

En
Fastapi django python (python)