Skip to main content

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 model
  • errors: List of error models
  • query: Query parameters model
  • path: Path parameters model
  • response: 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)

Source distribution for drf-pydantic-openapi 0.6.5
File Size Uploaded
drf_pydantic_openapi-0.6.5.tar.gz 931.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for drf-pydantic-openapi 0.6.5
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.6.5 This release

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

1 release file

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page