Skip to main content

Dev-time conveniences for Django projects: autologin endpoint, dotfiles for LLM agents, gitignore self-check

Project description

django-dev-helpers

PyPI CI License: MIT Python Django

Dev-time conveniences for Django projects: autologin endpoint, dotfiles for LLM coding agents, agent help prompt, and gitignore self-check.

Features

  • Autologin endpoint — one URL logs in a user via token, no interactive login needed
  • Auth-state query toggles?__autologin__=tmp_off|logout|log_in on any URL to flip auth state in the browser without leaving the page
  • Dotfiles.dev_helpers_token, .dev_helpers_port, .dev_helpers_pg_*, .dev_helpers_redis_* written to project root for easy cat by LLM agents
  • Agent help prompt — copy-pasteable curl/psql/redis-cli commands printed at startup
  • Gitignore self-check — warns if dotfiles are not in .gitignore
  • Browser auto-open — opens autologin URL in browser after server starts
  • ALLOWED_HOSTS auto-injection — when started by run-site --bind 0.0.0.0, unions the discovered LAN hostnames/IPs into settings.ALLOWED_HOSTS so other devices on the network can reach the dev server without per-project edits
  • Live reload / tab reuse — open tabs refresh themselves on restart instead of piling up new ones
  • Production-safe — default-off, requires explicit enabled=True, raises on DEBUG=False

Installation

pip install django-dev-helpers
# or
uv add django-dev-helpers --group dev

Quick Start

  1. Add to INSTALLED_APPS:
INSTALLED_APPS = [
    # ...
    "django_dev_helpers",
]
  1. Enable in settings:
DJANGO_DEV_HELPERS = {"enabled": True}

Or via environment variable:

DJANGO_DEV_HELPERS_ENABLED=1 python manage.py runserver

That's it — autologin is wired automatically. On startup, the package will:

  • Generate an autologin token
  • Auto-install AutologinMiddleware into MIDDLEWARE so the autologin URL works without urls.py changes (refuses to load if DEBUG=False)
  • Write dotfiles to your project root
  • Check .gitignore
  • Print agent help after first request
  • Open browser at the autologin URL (falls back to / with a banner if the URL is somehow not wired)

If you'd rather wire the URL by hand (e.g. to mount it under a prefix), set {"autologin": {"middleware_autoinstall": False}} and add to urls.py:

from django_dev_helpers.urls import autologin_urlpatterns

urlpatterns = [
    *autologin_urlpatterns(),
    # ... your other URLs
]

Usage

Autologin URL (token-based)

T=$(cat .dev_helpers_token)
curl -L "http://localhost:8000/__autologin__/?token=$T"

Auth-state toggles (browser-friendly)

Once AutologinMiddleware is wired (the default), every request is scanned for a toggle query parameter. Drop it onto any URL — the middleware handles it before URL resolution.

URL on any view Effect
https://localhost:8000/some/page/?__autologin__=tmp_off Render this one request with request.user = AnonymousUser. Session unchanged — the next plain request is logged in again. Toggle param stripped from request.GET before the view sees it.
https://localhost:8000/some/page/?__autologin__=logout django.contrib.auth.logout(request) — ends the session. 302 to the same path with the toggle stripped; other query parameters preserved.
https://localhost:8000/some/page/?__autologin__=log_in (or login) Log in the configured user (autologin.user_lookup_field / user_lookup_value). 302 to the cleaned URL. No URL token required — the localhost host allowlist is the trust signal.

Unknown values pass through silently (likely typos). Off-host requests pass through identically — the toggles do not announce their existence to unauthorized hosts.

Rename the parameter via autologin.query_param, or set it to "" / None to disable the toggle layer while keeping the path-based /__autologin__/ URL working. Full details and threat model: docs/autologin.md.

Middleware ordering

AutologinMiddleware is auto-appended at the end of settings.MIDDLEWARE during AppConfig.ready(). That works because the toggles need SessionMiddleware, AuthenticationMiddleware, and MessageMiddleware to have already run by the time we look at the request — sessions for logout/log_in, request.user set up so tmp_off can override it, and request._messages for the path-based view's flash_message.

If you install the middleware manually (with autologin.middleware_autoinstall=False), place it after those three:

MIDDLEWARE = [
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    # ... your other middleware ...
    "django_dev_helpers.middleware.AutologinMiddleware",
]

Putting it before SessionMiddleware/AuthenticationMiddleware/MessageMiddleware will break logout, log_in, and flash_message respectively.

Auto-injected ALLOWED_HOSTS (with run-site)

When the dev server is started via run-site >= 0.13.0 with a non-loopback bind (e.g. run-site run --bind 0.0.0.0), run-site discovers the machine's mDNS hostname and primary LAN IP and exports them under DEV_HELPERS_ALLOWED_HOSTS. At AppConfig.ready(), django-dev-helpers reads that env var and unions the entries into settings.ALLOWED_HOSTS.

This means a phone on the same Wi‑Fi can hit http://your-mac.local:8000/ without you touching settings.py — even when the project hard-codes ALLOWED_HOSTS = ['localhost'].

Behaviour:

  • Idempotent — safe under runserver autoreload, no duplicate entries.
  • Gated by is_active() (i.e. DJANGO_DEV_HELPERS_ENABLED=1) — the env var is ignored unless the helper is fully activated, so a leftover var in production cannot mutate ALLOWED_HOSTS.
  • No-op when settings.ALLOWED_HOSTS already contains * (your setting takes precedence — adding more entries accomplishes nothing).
  • No-op when the env var is unset (default --bind 127.0.0.1 runs).

You can also set DEV_HELPERS_ALLOWED_HOSTS=host1,host2,... manually when running outside run-site if you want the same convenience.

Live reload / tab reuse

With live_reload.enabled (default), a tiny SSE client is injected into every text/html page. When the server comes back after a restart (or Django autoreload), the already-open tab reloads itself instead of you getting a fresh duplicate tab. On restart, dev-helpers (and run-site, if you use it) skip opening a new browser tab when a live tab is already connected. See docs/configuration.md#live_reload for the knobs (enabled, reuse_tabs, grace_seconds) and the CSP / closed-tab caveats.

Management Commands

python manage.py dev_helpers_doctor          # Full diagnostic
python manage.py dev_helpers_print_help      # Print agent prompt
python manage.py dev_helpers_check_gitignore # Check .gitignore entries (read-only)
python manage.py dev_helpers_fix_gitignore   # Add missing .gitignore entries (idempotent)

dev_helpers_fix_gitignore is the one you want when you see the "missing entries from .gitignore" warning on startup — it appends the missing dotfile names (and only those) without reordering existing rules. Pass --dry-run to preview. See docs/configuration.md#gitignore for the full contract.

Documentation

Configuration

All configuration via settings.DJANGO_DEV_HELPERS dict. See configuration docs for full reference.

DJANGO_DEV_HELPERS = {
    "enabled": True,
    "autologin": {
        "user_lookup_field": "username",
        "user_lookup_value": "admin",
        "url_path": "__autologin__/",
        "redirect_to": "/",
        # Middleware that handles the autologin URL + auth-state toggles.
        # Auto-appended to settings.MIDDLEWARE; refuses to load when DEBUG=False.
        "middleware_autoinstall": True,
        # Name of the query toggle (?__autologin__=tmp_off|logout|log_in).
        # Set to "" or None to disable the toggle layer.
        "query_param": "__autologin__",
    },
    "dotfiles": {
        "enabled": True,
    },
    "agent_help": {
        "auto_print": True,
    },
    "browser_open": {
        "enabled": True,
    },
    "live_reload": {
        "enabled": True,     # inject SSE client; open tabs reload on restart
        "reuse_tabs": True,  # don't open a new tab when one is already live
        "grace_seconds": 2.0,
    },
    "gitignore": {
        "mode": "warn",  # warn | auto-add | error | off
    },
}

Security

This package exposes an autologin backdoor for development. It is always off by default:

  • enabled must be explicitly set to True (via settings or env var)
  • Raises ImproperlyConfigured if DEBUG=False and serving HTTP
  • Autologin view verifies token via hmac.compare_digest (timing-safe)
  • Only accepts requests from localhost/127.0.0.1 by default
  • Returns 404 (not 403/401) on any failure — endpoint appears non-existent

Never install this package in production. Add it only to dev dependencies.

Requirements

  • Python >= 3.11
  • Django >= 4.2

Supported versions

Combinations exercised on every push by the CI matrix (.github/workflows/ci.yml):

Python 3.11 Python 3.12 Python 3.13
Django 4.2
Django 5.0
Django 5.1
Django 5.2
Django 6.0

Django 6.0 requires Python ≥ 3.12, so the (3.11, 6.0) cell is excluded from CI.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_dev_helpers-0.1.12.tar.gz (115.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_dev_helpers-0.1.12-py3-none-any.whl (45.8 kB view details)

Uploaded Python 3

File details

Details for the file django_dev_helpers-0.1.12.tar.gz.

File metadata

  • Download URL: django_dev_helpers-0.1.12.tar.gz
  • Upload date:
  • Size: 115.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for django_dev_helpers-0.1.12.tar.gz
Algorithm Hash digest
SHA256 ab9debce7e8521955622892e4f629ac83f9e7dc0f9a4cc148e59e78f580e5475
MD5 8c45328e3df4529d46132a8a0b93e83e
BLAKE2b-256 480deceac70ca9bd3d41d96ab73cd60c5c4a9dc46d570c84899f90c18ba1234b

See more details on using hashes here.

File details

Details for the file django_dev_helpers-0.1.12-py3-none-any.whl.

File metadata

File hashes

Hashes for django_dev_helpers-0.1.12-py3-none-any.whl
Algorithm Hash digest
SHA256 935a500d74d041996355a39ee057d2f2cd313f59662047f31f14e337a2d98d4b
MD5 80f5b92819e5eeee34d94ec572781d2b
BLAKE2b-256 a8663f2fac9f16f251aa7169194a0f5a54e3cafde6c273f02ddbc3d6db753e61

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page