Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

django-bolt

Experimental. django-bolt is 0.10.x, classified Alpha by its authors, needs Python 3.12, and serves from Rust. The adapter passes all twelve conformance cases. Its surface is small — the three seams django-bolt documents, and nothing private — and its extra carries <1. See Stability.

pip install "dynamic-config-py[django-bolt]"        # Python 3.12+
from dynamic_config import DynamicConfig
from dynamic_config_web import token_guard
from dynamic_config_web.django_bolt import api, snapshot

config = DynamicConfig(Database, key="db").file("config.toml").env("APP_")

bolt = api(config, guard=token_guard(os.environ.get("CONFIG_TOKEN", "")))


@bolt.get("/")
async def index():
    db = snapshot()
    return {"host": db.host, "pool": db.pool.max_size}

examples/07_django_bolt.py runs all of it.

A factory, not setup(app, config)

django-bolt takes its lifespan and its middleware as constructor arguments. A wiring added after the BoltAPI exists would have to reach past the API into private attributes, which is not a thing to build on a 0.10 library — so api() builds the BoltAPI for you and passes every other keyword straight through:

bolt = api(config, prefix="/v1", django_middleware=True, middleware=[Timing])

For an application that must build its own, the three pieces are public and composing them by hand is exactly what api() does:

from django_bolt import BoltAPI
from dynamic_config_web.django_bolt import ScopeMiddleware, lifespan, router

bolt = BoltAPI(lifespan=lifespan(config), middleware=[ScopeMiddleware])
bolt.include_router(router(wiring, guard=guard))

Django first

django-bolt is a Django application: settings must be configured and django.setup() called before a BoltAPI exists. That is django-bolt's requirement, not this adapter's, and it is why the example configures Django at the top.

The Django adapter and this one are independent — a project can use either, or both, and each keeps its own wiring.

The middleware

django-bolt's middleware is Django's shape: get_response in, a response out, awaited inside the middleware's own coroutine. A contextvars token set there is visible to the handler, so the scope goes where it goes in every other adapter — in middleware, with nothing for the caller to remember. (Robyn is the one framework where that does not hold.)

Response annotations

The routes this adapter registers are annotated -> Any. django-bolt validates a response against its handler's return annotation, and -> Response makes it check the body against the Response class — which a dict body then fails. Any is the annotation that says "this handler builds its own response".

Worth knowing if you write your own health route beside these.