stack.menu

Django

Data-heavy products with an ORM, forms, accounts and admin.

Django · PostgreSQL · uv · pytest

Complete guide (Markdown) · Structured record (JSON)

Original source review: 2026-10-10. Core guidance rechecked: 2026-10-13. Check scope. Dependency combinations and setup need project-specific qualification.

Use cases

Choose it when

Consider another path when

Working practices

Tools by job

Packaging and environments: uv + pyproject.toml + committed uv.lock

One project entry point for dependencies, Python selection, execution and reproducible sync.

Pin a compatible Python minor and resolve actual package versions at implementation; do not hand-edit uv.lock. Keep environments and caches in a local development workspace.

Lint and format: Ruff

Fast lint and formatting feedback with one configuration.

Ruff does not replace static typing, tests, authorization checks or runtime validation.

Static typing: mypy + django-stubs plugin

Django-aware stubs and plugin improve checks around ORM and settings.

Check the django-stubs compatibility table for the selected Django/Python/mypy combination; plugin imports application settings.

Testing: pytest + pytest-django

Database fixtures and Django integration while retaining pytest conventions.

Set DJANGO_SETTINGS_MODULE; use isolated PostgreSQL tests for constraints and transactions. Unit tests alone miss request and migration behavior.

Database and migrations: PostgreSQL + Django ORM/migrations + Psycopg

Use the framework's existing data layer and schema history.

Review schema/data migrations and query counts; run production-relevant DB tests. Do not introduce SQLAlchemy as a second default ORM.

Validation: Django Forms/ModelForms plus domain checks and DB constraints

Form lifecycle handles submitted values and field errors.

Model saving is not a substitute for form/domain validation; enforce invariants at the appropriate transaction boundary.

Authentication: Django auth, sessions, permissions and CSRF protection

Built-in accounts and session conventions fit browser products.

Object/tenant permissions still need explicit implementation and tests; do not expose the admin as the product UI by default.

Background jobs: Celery + a configured durable broker

Documented Django integration for off-request work.

Broker required; enqueue after commit, retry only safe effects. Django Tasks built-in backends do not supply production workers or durable queues. Celery is a separate integration, not automatically a django.tasks backend.

Long-running durable agents: Temporal Python SDK when recovery across restarts is required

Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits.

Adds a service and operational cost. Keep external I/O in activities, make side effects idempotent, test replay and cancellation; no end-to-end integration was run.

Deployment: Container or managed Python service; WSGI for sync applications, ASGI when justified

Use the Django production deployment interface and checklist.

Choose/pin a compatible application server at implementation; never deploy runserver. Configure secrets, HTTPS, static assets, health checks and backups.

Application logging: Python logging with configured handlers

Shared standard logging captures application and dependency diagnostics

Configure logging at entry point, redact credentials and add request/job IDs, duration and failure context. Persist logs on the execution platform; metrics/tracing backend is a separate operational choice.

Bounded external-call retries: Tenacity only for retryable transient failures

Explicit stop/wait/filter rules support controlled retries

Install tenacity; set attempt/deadline limits, jitter and exception filters. The bare decorator retries forever without delay; do not stack retries with SDK/worker retries or repeat non-idempotent effects without keys.

Transactional email: django.core.mail + selected SMTP backend

Built-in mail wrappers and test backends fit account/product messages

Configure TLS, sender and backend; test HTML/text content and enqueue required delivery. Delivery and bounce monitoring remain provider responsibilities.

Uploads and file storage: Django FileField + configured storage backend

Framework file APIs separate model metadata from storage

Configure storage for the selected host; validate upload size/type and authorize serving. Local MEDIA_ROOT is unsuitable for unshared ephemeral replicas; choose an external backend when required.

Build with the stack’s strengths

Architecture and developer workflow.

Django organizes projects into applications, with conventional URL/view/model boundaries and integrated authentication. Recommendation: keep domain operations and permissions reusable across HTTP views, admin actions and workers. Optional Celery and Channels are separate execution/messaging systems rather than core Django features.

Version scope: Django 6.0 versioned docs; Celery 5.6.3 and Channels 4.3.2 current docs fetched 11 October 2026. The Django 6 Tasks API is version-specific and does not imply an existing Django 5.2 project should upgrade or abandon Celery. Pin actual Python/package versions before qualifying composition. · Reviewed 2026-10-11

Architecture boundaries

Tools and feedback

Translations to avoid

For an existing application

Keep the contracts while you change the stack.

These are documented options and proposed checks. Inspect the actual source application before adopting a transition.

Data and schema

Inspect the source

Capture schema, account IDs, database constraints and model/write side effects. Migration history is framework-owned metadata and must be reconciled deliberately when an existing schema changes owner.

During coexistence

Recommendation: retain one domain writer and schema runner; add compatible fields and move one application/domain boundary while old code still reads new records. Use historical models for Django data migrations as documented.

Target design

Django models/migrations with explicit transaction.atomic boundaries for related database writes. Recommendation: delay field deletion until the rollback reader retires.

Rollback

Recommendation: restore the old writer while retaining additive fields; rehearse reverse migrations on a disposable copy and reconcile non-reversible data operations.

Benefits and prerequisites

Recommendation: coherent model and migration ownership makes a domain boundary reviewable.
Requires: Tested schema mapping and explicit writer transfer.
Tradeoffs: Database reversal may be irreversible for data operations; application objects/cache state also need reconciliation.

Checks before transfer

  • Create in each permitted writer and read in both runtimes; compare identifiers, null values, timestamps and constraint failures.
  • Fail inside transaction.atomic and verify database writes roll back; inspect whether in-memory/cache state requires explicit restoration.
Jobs and schedules

Inspect the source

Inventory task names, argument serializer, broker/result backend, retry/acknowledgement policy, periodic schedule and ready/delayed/failed/running work. Django 6 Tasks and Celery payloads are distinct contracts.

During coexistence

Recommendation: keep old consumers for old tasks; isolate new categories and route producers deliberately. Retain the existing scheduler until an explicit one-owner transfer. Qualify any Django Tasks backend separately from the task API.

Target design

Celery with a selected broker/optional result backend, or a qualified Django 6 executing backend. Schedule dispatch after database commit; recommendation: add recoverable outbox delivery when a crash can occur before broker acceptance.

Rollback

Recommendation: pause new producers, retain consumers for accepted payloads and reconcile completed effects before switching categories back.

Benefits and prerequisites

Recommendation: execution can migrate by task category while the old backlog remains executable.
Requires: Qualified payload fixtures, retained consumers and one schedule owner.
Tradeoffs: Two task systems may be operated; a framework API switch does not translate backlog or broker guarantees.

Checks before transfer

  • Capture a task envelope and run it through its intended consumer, including argument conversion and missing-record behavior.
  • Rollback the domain transaction and verify no dispatch; kill after an external effect and validate replay-safe completion.
  • Account for delayed/retry/failed/in-flight tasks and confirm one periodic enqueue for each transferred schedule.
Identity and authorization

Inspect the source

Record authentication backend, user mapping, session engine/cookie name, serializer, expiry and revocation. Django database, cached_db, cache-only and signed-cookie sessions have different persistence/failure behavior.

During coexistence

Recommendation: retain a shared identity authority or qualified exchange; do not treat Redis key sharing as session-format compatibility. Keep every resource permission enforced in the target view/operation.

Target design

Django authentication with a selected session backend. cached_db writes through to database/cache and reads the database on cache misses; recommendation: prefer it over cache-only sessions when eviction logout is unacceptable.

Rollback

Recommendation: preserve previous identity/session contracts through the rollback window and retain revocation state during traffic reversal.

Benefits and prerequisites

Recommendation: a durable session authority can preserve access through cache eviction.
Requires: Configured database sessions, compatible account mapping and tested revocation.
Tradeoffs: Write-through caching adds operations; cookie continuity across runtimes still requires a decoder/exchange or planned reauthentication.

Checks before transfer

  • Login in the old system, access the Django feature, then logout/expire/revoke and verify both deny unauthorized operations.
  • Evict the selected session cache and confirm behavior matches the chosen engine; test another tenant’s identifier with a valid login.
Realtime transport

Inspect the source

Capture WebSocket protocol, group/event names, authentication and required missed-event behavior. Channels channel layers carry application-level events, not a universal client protocol.

During coexistence

Recommendation: keep old client endpoints, bridge versioned domain events and route room/user cohorts including reconnects. Designate one committed-change publisher; use the configured shared layer for multiple processes.

Target design

Channels with channels_redis when using the documented official production channel layer. Recommendation: reconstruct/replay from persistent domain state when missed broadcasts matter.

Rollback

Recommendation: retain the previous endpoint/event envelope and route cohorts back including their reconnects; avoid replaying already-applied effects.

Benefits and prerequisites

Recommendation: a shared channel layer enables cross-process fanout.
Requires: Configured Redis layer, matching consumers/events and authorized subscriptions.
Tradeoffs: Redis remains operated; transient fanout alone does not provide durable business-message recovery.

Checks before transfer

  • Connect subscribers to separate processes and verify one committed change reaches both authorized groups.
  • Restart/disconnect during an event and verify reconnect obtains missing domain state; revoke access and confirm rejected subscriptions.
Caching and shared state

Inspect the source

Inventory key versions/prefixes, serializers, TTLs and invalidation, separating disposable values from session/coordination ownership. Django local-memory cache is per-process even though it is thread-safe.

During coexistence

Recommendation: use separate namespaces for changed representations and invalidate both old/new readers. Retain shared storage for cross-process requirements; move only reconstructible local data to LocMemCache.

Target design

A deliberately selected Django cache backend with configured timeout/key version. Recommendation: use local caches only where node/process staleness is accepted and rebuilding is safe.

Rollback

Recommendation: restore old namespace/backend routing and repopulate from authoritative data without treating cache contents as business records.

Benefits and prerequisites

Recommendation: reconstructible caching can change independently of domain writes.
Requires: Defined staleness, invalidation and data ownership.
Tradeoffs: Per-process caches duplicate state; sensitive filesystem cache locations/serialization require care as the docs explain.

Checks before transfer

  • Warm two processes, commit a source update and verify both readers meet the stated staleness policy.
  • Restart or empty only the dedicated cache and verify reconstruction; session/permission correctness must remain intact.
Delivery and recovery

Inspect the source

List production application server, settings/secrets, migrations, static/media handling, Celery worker/beat and Channels processes. Celery requires only one scheduler for a schedule at a time.

During coexistence

Recommendation: keep both process inventories and one named migration/schedule owner during coexistence. Define promotion thresholds for outcomes, queue age and denied access rather than promoting from a clean startup alone.

Target design

An explicitly configured deployment following Django’s checklist, plus independently supervised selected workers and scheduler. Recommendation: document restored database/session/queue consistency.

Rollback

Recommendation: restore old routing/settings and schedule ownership explicitly; preserve accepted tasks and reconcile effects before replay.

Benefits and prerequisites

Recommendation: production checks and role ownership make recovery responsibilities visible.
Requires: Actual production settings and a rehearsed restore/restart.
Tradeoffs: check --deploy detects configuration issues, not end-to-end job, permission or restore correctness.

Checks before transfer

  • Run the deployment checks against intended settings and exercise an authorized/denied request after a disposable restore.
  • Stop a worker and verify queued work is visible; restart it, then verify one scheduler and intended recovery behavior.

Read the migration workflow →

Setup

  1. In a new local source directory in a local development workspace: uv init; choose and pin a supported Python minor, then uv add django 'psycopg[binary]'. Resolve compatible versions and commit uv.lock.
  2. uv add --dev ruff mypy django-stubs pytest pytest-django
  3. uv run django-admin startproject config . ; then uv run python manage.py startapp core
  4. Configure installed apps, PostgreSQL credentials from the environment, auth/session settings, pytest DJANGO_SETTINGS_MODULE and the django-stubs mypy plugin/settings module.
  5. Implement one authorized vertical slice; generate migrations with uv run python manage.py makemigrations, review them, then uv run python manage.py migrate against a disposable development DB.
  6. Add Celery only for actual queued work; configure broker, worker and after-commit enqueueing. Add Temporal only when durable multi-step recovery is required.
  7. Document application server, static asset collection, migration release ordering, worker start/restart and rollback. Run verification below before deployment.

Verification

Run these in the configured application; they are instructions, not recorded passes.

uv sync --locked
uv run ruff check .
uv run ruff format --check .
uv run mypy core config
uv run pytest
uv run python manage.py check
uv run python manage.py makemigrations --check --dry-run
uv run python manage.py migrate --check
uv run python manage.py check --deploy --settings=config.production

Open questions

Sources