Django Quickstart
Protect a Django view with Baldur. No Redis, no Docker, no environment variables. The in-memory fallback covers the whole first run.
Supports Python 3.11–3.13 and Django 4.2 / 5.2 LTS / 6.x. Assumes you have built a Django app before.
1. Install
pip install baldur-framework[django]
2. Add Baldur to your settings
Add baldur.adapters.django to INSTALLED_APPS. Its app config calls
baldur.init() on startup for you — there is nothing else to wire.
"""Minimal Django settings for the Baldur quickstart.
Zero infrastructure: in-memory SQLite + Baldur's in-memory fallback (no Redis,
no env vars). Adding ``baldur.adapters.django`` to ``INSTALLED_APPS`` calls
``baldur.init()`` automatically on startup via the app's ``ready()`` hook.
Production: see the "Add Redis for production" appendix in
``docs/getting-started/django.md`` — the in-memory fallback is single-process
only and is NOT safe for multi-worker deployments.
"""
from __future__ import annotations
SECRET_KEY = "quickstart-insecure-key-do-not-use-in-production" # noqa: S105
DEBUG = True
ALLOWED_HOSTS = ["*"]
INSTALLED_APPS = [
"django.contrib.contenttypes",
"django.contrib.auth",
# Baldur Django integration — calls baldur.init() on startup.
"baldur.adapters.django",
]
ROOT_URLCONF = "urls"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": ":memory:",
}
}
USE_TZ = True
3. Protect a view
@baldur.protected("demo") wraps the view in Baldur's composed resilience
pipeline (circuit breaker on by default):
"""Minimal Django view protected by Baldur's marquee facade.
``@baldur.protected("demo")`` wraps the view in Baldur's composed resilience
pipeline (circuit breaker on by default). With zero configuration it uses the
in-memory fallback — no Redis, no env vars. See
``docs/getting-started/django.md`` for the 5-minute walkthrough.
"""
from __future__ import annotations
from django.http import HttpRequest, JsonResponse
import baldur
@baldur.protected("demo")
def demo(request: HttpRequest) -> JsonResponse:
"""Return a JSON payload through Baldur's resilience pipeline."""
return JsonResponse({"status": "ok", "service": "demo"})
Route it:
"""URL configuration for the Baldur Django quickstart."""
from __future__ import annotations
from django.urls import path
from views import demo
urlpatterns = [
path("demo/", demo),
]
4. Run it
Start the dev server and call the route:
python manage.py runserver
curl http://127.0.0.1:8000/demo/
# {"status": "ok", "service": "demo"}
That's it. The response just travelled through a circuit breaker.
See Baldur's events
Baldur logs to stdout automatically. Raise the log level to watch circuit breaker and rate-limit events as you exercise the endpoint:
export BALDUR_LOG_LEVEL=INFO # circuit opened/closed, rate-limit blocks, ...
Verify without a browser
The quickstart ships a smoke test that drives the view through Django's in-process test client — no server, no infra:
pytest examples/quickstart_django/test_smoke.py
Browse the full runnable app:
examples/quickstart_django/.
Going to production
The in-memory fallback is single-process only
The zero-config path uses Baldur's in-memory cache. It keeps state in a
per-process store, so copying this quickstart into a multi-worker
deployment (gunicorn --workers N, uvicorn --workers N) does not
degrade gracefully: idempotency keys, rate-limit counters, and circuit
breaker state diverge silently per worker. That breaks correctness,
not just scale. The in-memory store also grows unbounded. This is a
hazard, not a tuning knob: give Baldur a shared backend before you run
more than one worker.
Point Baldur at Redis so all workers share state. No code changes needed: set one environment variable before starting the server:
pip install baldur-framework[django,redis]
export BALDUR_REDIS_URL=redis://localhost:6379/0
That is the only addition the production path needs over the quickstart path.