Интеграция двух фреймворков: 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