Skip to main content

Drop-in interactive API docs for Django — Swagger UI, FastAPI-style, with zero decorators and zero extra dependencies.

Publish Package version Monthly downloads

Python Django License

GitHub Stars


Documentation: https://djo.readthedocs.io

Source Code: https://github.com/NEFORCEO/djo


djo turns any Django project into a self-documenting API. Add one line to INSTALLED_APPS and a full Swagger UI shows up at /docs — no urls.py edits, no serializers, no decorators on your views. It walks your project's own urlpatterns and builds the OpenAPI schema from what it finds.

Key features:

  • Zero config — the only thing you touch is INSTALLED_APPS. No urls.py changes, no middleware to wire up by hand.
  • Automatic — paths, path parameters and HTTP methods are all inferred by walking the URLconf and the views it points to. Nothing to decorate, nothing to register.
  • Typed path params — <int:pk>, <uuid:token>, <slug:handle> are mapped to real OpenAPI types straight from Django's own path converters.
  • Query params — request.GET.get("page", 1) / request.GET["tag"] style access is picked up automatically, with type and required-ness inferred from how it's read.
  • Smart request bodies — instead of a blank {}, djo reads a handler's source for request.POST.get(...) / request.data[...] style access and pre-fills the example with the fields it actually uses.
  • DRF serializer aware — if a view declares serializer_class, djo reads the real fields straight off it (types, required, read_only/write_only, choices) instead of guessing from source.
  • Auth-aware — permission_classes, authentication_classes and LoginRequiredMixin are detected automatically and surfaced as a Swagger Authorize button (cookie or bearer, depending on what the view uses).
  • Error responses — status codes referenced via status=404, status.HTTP_400_BAD_REQUEST, or raised via Http404/DRF exceptions are added to the schema alongside the success response.
  • Interactive — "Try it out" works against your real endpoints out of the box; the CSRF cookie is forwarded automatically for unsafe methods.
  • No extra dependencies — pure Django. No Pydantic, no DRF required (though it plays nicely with DRF views if you have them).

Requirements

Python 3.10+, Django 5.2+.

Installation

$ pip install djo

Example

Add "djo" to INSTALLED_APPS:

INSTALLED_APPS = [
    ...,
    "djo",
]

That's it. Run your project as usual:

$ python manage.py runserver

Check it

Go to http://127.0.0.1:8000/docs.

You will see the automatic interactive API documentation, generated straight from your urlpatterns:

Expand any route to inspect path parameters and, where djo can infer them, request body fields. Click Try it out to execute the request for real and see the actual response — session auth and CSRF are handled for you.

Configuration

Everything is optional — djo works with sane defaults out of the box. Override title, version, description, or the docs paths themselves via a DJO dict in settings.py:

DJO = {
    "TITLE": "My API",
    "VERSION": "1.0.0",
    "DESCRIPTION": "Internal API for the mobile app.",
    "DOCS_URL": "/docs",
    "OPENAPI_URL": "/openapi.json",
}

Enabling in production

/docs and /openapi.json expose your whole API surface — paths, inferred request bodies, auth requirements, error codes. ENABLED defaults to settings.DEBUG, so a plain install never serves them on a production deployment by accident. Turn them on explicitly, ideally behind your own auth check:

DJO = {
    "ENABLED": True,
    "GATE": "myapp.docs.is_staff",  # def is_staff(request) -> bool
}

GATE (a callable or dotted import path) runs on every docs request; a falsy return makes djo fall through as if it weren't installed.

Self-hosting Swagger UI

By default the Swagger UI assets load from jsDelivr, pinned to an exact version and verified with Subresource Integrity hashes. For offline or strict-CSP deployments, point them at your own copies:

DJO = {
    "SWAGGER_CSS_URL": "/static/swagger-ui/swagger-ui.css",
    "SWAGGER_JS_URL": "/static/swagger-ui/swagger-ui-bundle.js",
    "SWAGGER_PRESET_JS_URL": "/static/swagger-ui/swagger-ui-standalone-preset.js",
}

Overriding a URL drops its bundled SRI hash; pass SWAGGER_CSS_SRI / SWAGGER_JS_SRI / SWAGGER_PRESET_JS_SRI to keep integrity checks on your own assets.

How it works

  • DjangoAPIConfig.ready() inserts djo.middleware.DjangoAPIMiddleware into settings.MIDDLEWARE the moment the app is loaded — before Django builds its middleware chain — which is what lets a single INSTALLED_APPS entry serve /docs and /openapi.json with no urls.py changes. It goes right after SecurityMiddleware (or at the front if that isn't installed), so HTTPS redirects and security headers still apply to the docs page.
  • The middleware intercepts those two paths ahead of normal URL resolution, but only for safe HTTP methods, only when ENABLED (default: settings.DEBUG), and only when the optional GATE callback allows it; every other request — and every gated-out one — passes straight through untouched.
  • djo/generator.py walks get_resolver().url_patterns recursively, resolving path() converters into OpenAPI parameter types and reading each view's docstring for a summary.
  • HTTP methods are inferred from class-based views (Django's View or DRF's APIView/api_view) by checking which handlers they actually implement; plain function-based views default to GET.
  • Request/response bodies prefer a view's declared serializer_class (its fields are read directly, nothing is sent over the network) and fall back to a light, best-effort read of the handler's own source — pattern matching for body/query access, no execution of your views.
  • Auth requirements and error status codes are inferred the same way: straight off class attributes for permissions/authentication, and off the handler's source for raised exceptions and explicit status codes.

Try the demo project

The repo ships a throwaway Django project under test/ wired up with a couple of sample endpoints, just to poke at the Swagger UI:

$ cd test
$ python manage.py runserver

Then open http://127.0.0.1:8000/docs.

Metadata

Release files for djo 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for djo 0.2.3
File Size Uploaded Provenance Actions
djo-0.2.3.tar.gz 18.2 kB Without provenance Details for djo-0.2.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for djo 0.2.3
File Interpreter ABI Platform Actions
djo-0.2.3-py3-none-any.whl Python 3 none any Details for djo-0.2.3-py3-none-any.whl

Total release size: 37.6 kB

Release files / djo-0.2.3.tar.gz

Download URL djo-0.2.3.tar.gz
Size 18.2 kB
Tags Source
SHA-256 checksum
How to use checksums
47118b375268527117886fe3dae7269e90ad598842bddab27b592fa5c69516e6
BLAKE2b-256 checksum
How to use checksums
123ac37ce71248487410c3928e79ba10d87497508e926b30abc12c93fe6b29be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / djo-0.2.3-py3-none-any.whl

Download URL djo-0.2.3-py3-none-any.whl
Size 19.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ef604b6450e4981f9a5f5f7e6cdc40b3cb69497057640d14f16e5f63fa3e6dcc
BLAKE2b-256 checksum
How to use checksums
9df2625fadf14dcae3df337468533ad3e5be9d4e8e720eca1bda59bf2e6a392d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for djo 0.2.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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