Skip to main content

django-visualize-urls

Map every URL of a Django project with the access control of each route, as a standalone HTML page.

show_urls of django-extensions lists the routes of a project. This map arranges them as a tree of includes and tells, for each route, what protects it: login_required, a permission, a mixin, DRF permission classes, the admin site, LoginRequiredMiddleware... or nothing. The page has filter tiles, a search field and a meter on each include, and it needs no network access.

Installation

pip install django-visualize-urls

Add the app to the settings of your development environment:

INSTALLED_APPS = [
    # ...
    "django_visualize_urls",
]

Usage

python manage.py visualize_urls

writes url-map.html in the current folder. Open it in a browser.

Option Effect
--format html|json Standalone page (default), or the same data as JSON for scripts.
--output PATH, -o PATH File to write (default url-map.html or url-map.json); - writes to the standard output.
--urlconf DOTTED.PATH URLconf to map instead of ROOT_URLCONF.
--editor-root PATH Project root to put in the editor links, when the project runs in a container and the editor on the host.

For a project that runs in a container, the host shell expands $PWD before the command enters the container:

docker compose exec web python manage.py visualize_urls --editor-root "$PWD"

The map reads the URL resolver loaded in memory: it serves no request and sends no query to the database. The page lists the internals of the project (routes, views, file paths): keep it out of public places.

What the map recognizes

Each route falls in one of three categories.

  • Protected: an access control the map recognizes covers every method of the route.
  • Hint in code: no recognized control, but the code of the view, or of a decorator or mixin of the project, holds words such as is_authenticated or PermissionDenied. A control that covers some handlers only (method_decorator(login_required) on post()) is a hint too. A hint is to be read, not a proof.
  • No hint: neither. A public page, or a control done elsewhere (a middleware, a template, a function that the view calls).

Recognized controls:

  • login_required, permission_required (with its permissions), staff_member_required, user_passes_test, and the decorators of the project built on it, named after their variable: staff_required = user_passes_test(lambda u: u.is_staff) shows as staff_required.
  • method_decorator() on dispatch(), or on a single handler.
  • LoginRequiredMixin, PermissionRequiredMixin (with its permissions), UserPassesTestMixin.
  • Django REST framework: permission_classes other than AllowAny, compositions such as IsAuthenticated & ~IsAdminUser, @api_view functions, the methods of routed ViewSet actions.
  • The admin site: the views it serves require an active staff account, custom views wrapped with admin_view() included; its login page is public.
  • LoginRequiredMiddleware, or a subclass of it: every route except the views marked login_not_required (DRF marks its views so).

The map also shows the methods a route answers (require_POST, require_http_methods, the handlers of a class-based view), the routes exempt from CSRF checks (csrf_exempt, and DRF views, which APIView.as_view() exempts), the names shared by several routes, the routes without a name, and the other decorators (never_cache, cache_page...).

A decorator is named after the code of the wrapper it leaves in the __wrapped__ chain: functools.wraps copies the name of the view onto the wrapper, but not its __code__. Its arguments, such as the test of user_passes_test, are read from the closure of the wrapper.

Settings

All keys are optional:

VISUALIZE_URLS = {
    "HINTS": ["check_api_key("],
    "NEUTRAL_DECORATORS": ["require_htmx"],
    "ACCESS_DECORATORS": ["shop.decorators.partner_required"],
    "EDITOR_URL": "vscode://file/{path}:{line}",
}
Key Default Meaning
HINTS [] Strings that reveal a hand-written check in project code, added to the built-in words. For a check done in a function the view calls (a webhook signature), list that function: "verify_signature(".
NEUTRAL_DECORATORS [] Decorators that do not control access: their code is not searched for hints. For a decorator that answers 403 for another reason, such as a request that HTMX did not send.
ACCESS_DECORATORS [] Decorators that control access although nothing in their code says so: their routes count as protected.
EDITOR_URL "vscode://file/{path}:{line}" Link that opens a project view in an editor. {path} is the absolute path of the file without its leading slash, {line} its line. None removes the links.

Decorators are listed by name ("require_htmx") or by dotted path ("shop.decorators.require_htmx"). Other editors: "cursor://file/{path}:{line}", "zed://file/{path}:{line}", "pycharm://open?file=/{path}&line={line}".

Project and third-party routes

A route is the project's when it is declared in a URLconf module of the project (a TemplateView declared in urls.py counts) or served by a view of the project. Project code lives under settings.BASE_DIR (or, without it, the folder that holds the package of ROOT_URLCONF) and outside site-packages. A list of patterns has no module (admin.site.urls, include([...])): its routes are the project's when their view is. The page hides the third-party routes until you turn on the switch.

Limits

The map reads code, it does not run it. It does not see checks done in a middleware other than LoginRequiredMiddleware, in a template, in an override of get_permissions() or has_permission(), or in a function the view calls; the hints and the settings cover part of it. A view that cannot be read stays on the map, flagged with the error.

Requirements

Python 3.11 or later, Django 5.2, 6.0 or 6.1. Django REST framework is optional.

Development

uv sync
uv run coverage run -m pytest -m "not browser"
uv run coverage report
uv run ruff format
uv run ruff check

The tests run on a demo shop (tests/demo) with one route for each way of protecting a view, without database or network. Its map:

uv run django-admin visualize_urls --settings tests.settings --pythonpath .

The test of the page in a browser needs Playwright and Chromium, a large download:

uv sync --group browser
uv run playwright install chromium
uv run pytest -m browser

To release a version, set it (uv version --bump minor), move the changes of CHANGELOG.md under it, push, then publish a GitHub release whose tag is the version:

gh release create v0.2.0 --generate-notes

The publish workflow checks that the tag matches the version, builds the package, smoke-tests the wheel and the source distribution, then uploads them to PyPI with Trusted Publishing and PEP 740 attestations.

License

MIT

Metadata

Release files for django-visualize-urls 0.1.0

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

Source distribution (sdist)

Source distribution for django-visualize-urls 0.1.0
File Size Uploaded Provenance Actions
django_visualize_urls-0.1.0.tar.gz 40.3 kB With provenance Details for django_visualize_urls-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-visualize-urls 0.1.0
File Interpreter ABI Platform Actions
django_visualize_urls-0.1.0-py3-none-any.whl Python 3 none any Details for django_visualize_urls-0.1.0-py3-none-any.whl

Total release size: 67.6 kB

Release files / django_visualize_urls-0.1.0.tar.gz

Download URL django_visualize_urls-0.1.0.tar.gz
Size 40.3 kB
Tags Source
SHA-256 checksum
How to use checksums
b3453e5bf7acf7a036afbfd9de2e51be037d5d1b011418175f918eedec119c43
BLAKE2b-256 checksum
How to use checksums
e8460b65d5a8a4ccb463f4be48feea9c13106ba774f747b85c163a7ae5b78a00
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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}

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Release files / django_visualize_urls-0.1.0-py3-none-any.whl

Download URL django_visualize_urls-0.1.0-py3-none-any.whl
Size 27.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c728a7eedb726537a00da0d47d2eb1f4b7fd7a9cc4407eda61d75128445b3713
BLAKE2b-256 checksum
How to use checksums
9f8c784ebdd18c88dce5c98b76203827175972b97f7decd49e8e41a9295c17c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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}

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Security for django-visualize-urls 0.1.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_visualize_urls-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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