drf-pydantic-openapi
Generate OpenAPI schema with DRF code using Pydantic models. Supports referencing other services' components.
Installation
pip install drf-pydantic-openapi
Add to INSTALLED_APPS:
INSTALLED_APPS = [
...
"rest_framework",
"drf_pydantic_openapi",
]
Configuration
Add settings to your project's settings.py:
DRF_PYDANTIC_OPENAPI = {
"TITLE": "My API",
"DESCRIPTION": "API Documentation",
"API_VERSION": "1.0",
"OPENAPI_VERSION": "3.1.0",
"SERVERS": ["https://api.example.com"],
"INCLUDE_EMPTY_ENDPOINTS": False,
"REF_SOURCES": {
"service_B": "http://localhost:8000/openapi/schema.json",
"service_C": "http://localhost:8001/openapi/schema.json",
},
"SECURITY_DEFINITIONS": {
"BearerAuth": {
"type": "http",
"scheme": "bearer",
}
},
}
URL Setup
from django.urls import path, re_path
from drf_pydantic_openapi.views import (
get_schema_view,
DrfPydanticRedocView,
DrfPydanticSwaggerView,
DrfPydanticRapidocView,
)
urlpatterns = [
re_path(
"openapi/schema.json",
get_schema_view(
api_version="v1", # optional: filter by API version
tag_path_regex="/api/v1/", # optional: regex for extracting tags
permission_classes=[], # optional: DRF permission classes
authentication_classes=[], # optional: DRF authentication classes
).as_view(),
name="dpo_schema",
),
re_path("openapi/redoc", DrfPydanticRedocView.as_view(), name="redoc"),
re_path("openapi/swagger", DrfPydanticSwaggerView.as_view(), name="swagger"),
re_path("openapi/rapidoc", DrfPydanticRapidocView.as_view(), name="rapidoc"),
]
Or use the default URLs:
from django.urls import path, include
urlpatterns = [
path("openapi/", include("drf_pydantic_openapi.urls")),
]
Available endpoints with default URLs:
/openapi/schema.json- OpenAPI schema/openapi/docs- ReDoc documentation
Using the @docs Decorator
Parameters:
body: Request body modelerrors: List of error modelsquery: Query parameters modelpath: Path parameters modelresponse: Response model (overrides return type annotation)
from pydantic import BaseModel, Field
from rest_framework.views import APIView
from drf_pydantic_openapi.utils import docs
from drf_pydantic_openapi.errors import BadRequestError, NotFoundError
class PathParams(BaseModel):
book_id: str = Field(description="Book ID to retrieve")
class QueryParams(BaseModel):
include_author: bool | None = Field(default=None, description="Include author details")
class BookResponse(BaseModel):
id: str
title: str
class BookView(APIView):
@docs(errors=[NotFoundError, BadRequestError], path=PathParams, query=QueryParams)
def get(self, request, book_id: str) -> BookResponse:
"""
Retrieve a book by ID.
Returns the book details including title and metadata.
"""
...
Multiple Response Types
Use union types to define multiple possible responses:
class SuccessResponse(BaseModel):
data: dict
model_config = {"status_code": 200}
class PartialResponse(BaseModel):
data: dict
errors: list[str]
model_config = {"status_code": 207}
class BookView(APIView):
@docs(response=SuccessResponse | PartialResponse)
def get(self, request) -> SuccessResponse | PartialResponse:
...
Referencing External OpenAPI Components
Use RefType to reference models from other services' OpenAPI schemas:
from drf_pydantic_openapi.ref_utils import RefType
# Simple reference
BookModel = RefType("service_B", "BookModel")
class BookView(APIView):
def get(self, request) -> BookModel:
...
Extending Referenced Types
class CustomBookModel(RefType("service_B", "BookModel")):
# Add new fields
read_count: int
model_config = {
# Remove fields from referenced type
"ref_exclude": ("author", "internal_id"),
# Rename fields: (new_name, original_name)
"ref_rename": (("name", "book_name"),),
}
class PaginatedBookModel(BaseModel):
total: int
next: str | None
prev: str | None
data: list[CustomBookModel]
class BookListView(APIView):
def get(self, request) -> PaginatedBookModel:
...
Typed Exception Handler
Configure the exception handler to return typed error responses:
# settings.py
REST_FRAMEWORK = {
"EXCEPTION_HANDLER": "drf_pydantic_openapi.exception_handler.typed_exception_handler"
}
Usage:
from drf_pydantic_openapi.errors import BadRequestError, HttpError
from pydantic import BaseModel
# Using built-in errors
class SomeView(APIView):
@docs(errors=[BadRequestError])
def post(self, request):
raise BadRequestError(message="Invalid input")
# Custom error with custom response model
class ValidationErrorResponse(BaseModel):
message: str
fields: dict[str, str]
class ValidationError(HttpError):
status_code = 422
ResponseModel = ValidationErrorResponse
class SomeView(APIView):
@docs(errors=[ValidationError])
def post(self, request):
raise ValidationError(message="Validation failed", fields={"email": "Invalid format"})
Response format:
{
"detail": {
"message": "Bad request"
}
}
Release files for drf-pydantic-openapi 0.6.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| drf_pydantic_openapi-0.6.5.tar.gz | 931.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| drf_pydantic_openapi-0.6.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.9 MB
Release files / drf_pydantic_openapi-0.6.5.tar.gz
| Download URL | drf_pydantic_openapi-0.6.5.tar.gz |
|---|---|
| Size | 931.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1bf619a2e10aadb188fe61f10e51faf600f89103f753d733834825fd5335ba2b
|
|
BLAKE2b-256 checksum How to use checksums |
1e23f4db734b77a3ff91d102fe41c4964b508faed136cf7ea4ce8b1ff0abc72a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.12.12 Darwin/25.2.0
|
Release files / drf_pydantic_openapi-0.6.5-py3-none-any.whl
| Download URL | drf_pydantic_openapi-0.6.5-py3-none-any.whl |
|---|---|
| Size | 939.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
778042bb213677b0dd0f495c4d7db1ec9e142773be9b639ef9cf272d7aff0b56
|
|
BLAKE2b-256 checksum How to use checksums |
5c853f9c26c1d399842a25fc2b3443934f8b2815ef2b34c6f909ff98f13ac8ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.12.12 Darwin/25.2.0
|