Inspect Django development traffic directly in your console. DDRR logs request and response metadata, headers, and available bodies, with optional JSON and XML pretty-printing. Supports Python 3.11–3.14 and Django 5.2–6.1.
Warning: DDRR is intended only for trusted development environments. It logs headers—including authorization and cookie headers—and bodies without redaction. Do not enable it where this data or the resulting logs may be exposed to untrusted users.
- Request and response headers
- Request and response bodies when available
- Optional JSON and XML pretty-printing
- Colored output
- Synchronous and asynchronous middleware support
- Minimal setup
- No extra dependencies
-
$ pip install ddrr -
Add
"ddrr"toINSTALLED_APPS -
Insert
"ddrr.middleware.DebugRequestsResponses"first inMIDDLEWARE
Done! When you run runserver, you'll see requests and responses, including
headers and available bodies.
To adjust DDRR's logging behavior, read on...
import logging
DDRR = {
"ENABLE_REQUESTS": True, # enable request logging
"ENABLE_RESPONSES": True, # enable response logging
"LEVEL": "DEBUG", # ddrr log level
"PRETTY_PRINT": False, # pretty-print JSON and XML
"REQUEST_HANDLER": logging.StreamHandler(), # request log handler
"RESPONSE_HANDLER": logging.StreamHandler(), # response log handler
"ENABLE_COLORS": True, # enable colors if terminal supports it
"LIMIT_BODY": None, # limit request/response body output to X chars
}DDRR renders terminal control characters as visible escape sequences. Newlines
inside single-line fields such as paths and headers are escaped. Body text keeps
its original indentation for easy copying; lines beginning with DDRR's reserved
<- or -> markers receive a leading backslash to prevent forged log entries.
By default, pretty-printing is disabled. Set DDRR["PRETTY_PRINT"] to True
to enable it.
Pretty-printing of JSON and XML uses the Python standard library and requires no external dependencies.
- Request bodies that Django has already consumed are shown as unavailable.
- Streaming response bodies are not consumed and are shown as
<streaming>. - Bodies that are not valid UTF-8 are shown using Python's bytes representation.
LIMIT_BODY, when configured, truncates request and response bodies.
The middleware ddrr.middleware.DebugRequestsResponses sends request and
response objects to separate loggers. DDRR's formatters turn them into fixed,
human-readable output. By default, this is shown in your console, but you can
configure the handlers to send it elsewhere.
Run the bundled example from the repository root:
$ uv run python example/manage.py runserverThe index page links to JSON, XML, binary, streaming, and terminal-control examples.
PRs are always welcome!
For hacking on DDRR, make sure you are familiar with:
Install the locked tool versions using mise, sync the project environment using
uv, then install the pre-commit hooks. mise automatically creates and activates
the project's .venv when entering the repository.
$ mise install
$ uv sync
$ uv run pre-commit installThe pre-commit hooks will, among other things, use Ruff to lint and format Python code and ty to check types. The full pre-commit configuration exists in
.pre-commit-config.yaml.
With Docker running, run the GitHub Actions workflow locally using act:
$ mise run actPass additional act options after --, for example mise run act -- --list.
Workflow files are also checked with actionlint by pre-commit.
Run ty using the current Python interpreter and project environment:
$ ty checkRun tests using the current Python interpreter and currently installed Django version.
$ uv run pytestRun tests with every supported Python and Django combination:
$ uv run tox --colored noFrom the intended release checkout, build the wheel and source distribution into
dist/<version>/, where <version> matches pyproject.toml. For example, for
4.0.2, run uv build --out-dir dist/4.0.2. Then publish them with:
$ mise run publishThe task prompts for a PyPI API token without echoing it. For automation, supply
UV_PUBLISH_TOKEN through your secret manager or CI environment instead. The
token is passed to uv through its environment, not command-line arguments, and is
not saved by the task.
Only the current version's wheel and source distribution are uploaded to PyPI. Missing artifacts stop the task before it requests credentials. Already-published identical files are skipped, so a partially completed upload can be retried.
