cheat sheet

django

Package-level reference for Django on PyPI — install variants, LTS release cadence, ecosystem companions, and alternatives.

#pip#package#web#apiupdated 05-31-2026

django

What it is

django is a full-stack web framework first released in 2005 and maintained by the Django Software Foundation. It ships with an ORM, migrations, admin panel, authentication, forms, template engine, caching, and middleware — the "batteries included" philosophy taken to its logical end.

Reach for Django when you want a single coherent stack for a database-backed app, when you need an admin UI for free, or when you're building a team-sized codebase that benefits from strong conventions. Reach for Flask/FastAPI when you want a smaller surface area or are building a pure API with a different ORM.

Install

bash
pip install django

Output: (none — exits 0 on success)

bash
uv add django

Output: dependency resolved + added to pyproject.toml

bash
poetry add django

Output: updated lockfile + virtualenv install

bash
pip install "django[argon2]"         # argon2 password hashing
pip install "django[bcrypt]"         # bcrypt password hashing

Output: Django plus the named optional password-hashing backend

Versioning & Python support

  • Predictable feature-release cadence: a new minor release every 8 months, and a new major (X.0) release roughly every 2 years. Major bumps coincide with deprecation cleanups.
  • LTS releases are issued every 2 years and receive security fixes for ~3 years total. Recent LTS lines: 4.2 LTS (2023), 5.2 LTS (2025). Non-LTS releases are supported for ~16 months.
  • Supports Python 3.10+ on the latest stable line; older releases support 3.8/3.9. Each Django version explicitly lists supported Python versions.
  • Strict deprecation policy — features are deprecated for at least 2 releases before removal.

Package metadata

  • Maintainer: Django Software Foundation
  • Project home: github.com/django/django
  • Docs: docs.djangoproject.com
  • PyPI: pypi.org/project/django
  • License: BSD-3-Clause
  • Governance: Django Software Foundation (non-profit), elected Technical Board
  • First released: 2005
  • Downloads: ~50M+/month — the dominant full-stack framework in Python

Optional dependencies & extras

  • django[argon2] — installs argon2-cffi for Argon2 password hashing (the most secure built-in choice).
  • django[bcrypt] — installs bcrypt for bcrypt password hashing (interop with legacy systems).

Core dependencies pulled in automatically:

  • asgiref — async/sync bridge for async def views
  • sqlparse — SQL formatting for the debug toolbar / shell

Common companion packages typically installed alongside:

  • psycopg[binary] (or psycopg2-binary) — PostgreSQL adapter; preferred over MySQL for new projects
  • mysqlclient — MySQL/MariaDB adapter
  • gunicorn / uvicorn / daphne — production WSGI / ASGI servers
  • whitenoise — static-file serving without nginx
  • django-environ / python-dotenv.env configuration
  • django-debug-toolbar — request inspector for development
  • django-extensionsshell_plus, runserver_plus, and many utility commands
  • djangorestframework (DRF) — the canonical REST API layer
  • django-ninja — typed, FastAPI-style API layer for Django
  • celery + redis — background tasks
  • django-storages — S3, GCS, Azure blob storage backends
  • pillow — required for ImageField

Alternatives

PackageTrade-off
flaskMicroframework, sync, you pick the ORM. Use for small services or full stack control.
fastapiAsync, type-driven, auto OpenAPI. Use for new typed REST APIs without an admin UI.
litestarAsync, strict typing, high throughput. Use when raw API speed matters more than batteries.
django-ninjaAdd-on, not a replacement — typed APIs on top of Django models. Use to keep the admin/ORM but build typed endpoints.
tornado / aiohttpLower-level async servers. Use only when you want to build a framework yourself.

Common gotchas

  1. LTS vs non-LTS support windows differ. LTS = ~3 years of security fixes; non-LTS = ~16 months. Production projects on a non-LTS release have a short upgrade clock.
  2. psycopg2-binary is fine for dev, not production. It bundles a vendored libpq. For production prefer psycopg[binary] (the modern v3 driver) or psycopg2 built from source against the system libpq.
  3. DEBUG = True leaks secrets. The default error page renders settings + traceback. Never deploy with DEBUG = True. The SECURE_* checklist (python manage.py check --deploy) catches this and several other footguns.
  4. ALLOWED_HOSTS must be set in production. A request with an unrecognized Host header returns 400 — necessary security default, but a common first-deploy surprise.
  5. Migrations live in each app. A model change without python manage.py makemigrations produces silently-stale schema. CI should run makemigrations --check to catch missed migration files.
  6. async def views need an ASGI server. Running gunicorn (WSGI) with async views works but each request becomes a sync-to-async bridge — no real concurrency. Use uvicorn or daphne for true async.
  7. The django-admin vs manage.py distinction. django-admin works without DJANGO_SETTINGS_MODULE; manage.py auto-sets it from manage.py's parent. Use manage.py inside a project, django-admin startproject only to bootstrap.
  8. Third-party-app ordering matters. Apps listed earlier in INSTALLED_APPS win on template lookup, signal registration, and management-command shadowing. The convention is: Django apps first, third-party apps next, local apps last.

Production deployment

Django supports two deployment modes: WSGI (sync, gunicorn/uWSGI) and ASGI (async, daphne/uvicorn/hypercorn). Choose ASGI when you actually use async def views, websockets, or channels; otherwise WSGI is simpler and well-trodden.

bash
# WSGI — gunicorn (most common production setup)
pip install gunicorn
gunicorn myproject.wsgi:application \
  --workers 4 \
  --threads 2 \
  --worker-class gthread \
  --bind 0.0.0.0:8000 \
  --timeout 60 \
  --max-requests 1000 \
  --max-requests-jitter 50 \
  --access-logfile -

Output: classic Django prod server; pairs with nginx for TLS termination and static-file serving.

bash
# ASGI — daphne (Django Channels' reference server)
pip install daphne
daphne -b 0.0.0.0 -p 8000 myproject.asgi:application

Output: required if you use channels (websockets); also handles regular HTTP.

bash
# ASGI — uvicorn with workers
pip install "uvicorn[standard]"
uvicorn myproject.asgi:application --host 0.0.0.0 --port 8000 --workers 4 --proxy-headers

Output: fastest ASGI option in benchmarks; preferred for pure async apps.

python
# settings.py — required prod-only adjustments
import os
DEBUG = False
ALLOWED_HOSTS = os.environ["ALLOWED_HOSTS"].split(",")
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SECURE_HSTS_SECONDS = 31536000
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True

# Static files via WhiteNoise (no nginx required)
MIDDLEWARE = ["django.middleware.security.SecurityMiddleware",
              "whitenoise.middleware.WhiteNoiseMiddleware", ...]
STORAGES = {
    "staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}

Output: production-safe settings; manage.py check --deploy audits these automatically.

bash
# Deploy sequence inside a container/CI
python manage.py collectstatic --noinput
python manage.py migrate --noinput
python manage.py check --deploy
gunicorn myproject.wsgi:application -c gunicorn.conf.py

Output: standard 4-step boot — collect static assets, run migrations, audit security settings, start the server.

Version migration guide

Django's deprecation policy is the strictest in the Python ecosystem — features are deprecated for at least two releases before removal, so the migration path is well-marked. The big jumps in recent memory:

3.2 LTS → 4.0:

  • Default USE_TZ = True (timezone-aware datetimes by default).
  • pytz removed from core in favor of zoneinfo — keep pytz installed only if you depend on it.
  • django.utils.encoding.force_text() removed — use force_str().

4.2 LTS → 5.0:

  • db_default for model fields (DB-side defaults).
  • Async ORM methods — Model.objects.aget(), acreate(), afilter(), etc.
  • Form-field assume_scheme for URLField.
  • Python 3.10+ required.

5.0 → 5.2 LTS:

  • Composite primary keys via CompositePrimaryKey.
  • More async ORM coverage (related-manager methods).
  • BoundField API extensions.

Migration playbook for any major bump:

bash
# 1. Pin the new version in a branch, install
pip install --upgrade 'django~=5.2'

# 2. Surface deprecation warnings
python -W error::DeprecationWarning manage.py test

# 3. Run the deploy checklist
python manage.py check --deploy

# 4. Run migrations against a staging DB clone
python manage.py migrate

# 5. Run the full test suite + a smoke test of admin/API endpoints

Output: warnings → errors flag every line that needs attention; do not upgrade past LTS until all are addressed.

Security considerations

Django has the most opinionated security model of any Python framework — most defaults are safe, but a handful of settings have to be turned ON for production. manage.py check --deploy is the canonical audit.

  • DEBUG = False in prod. Non-negotiable. With DEBUG=True, the error page exposes settings and traceback.
  • SECRET_KEY from env; rotate via SECRET_KEY_FALLBACKS (Django 4.1+) for zero-downtime rotation.
  • ALLOWED_HOSTS must list every public hostname. Wildcards (*) are dangerous unless behind a strict LB.
  • CSRF protection is on by default. Don't disable it casually. AJAX must include the X-CSRFToken header (or post the form token).
  • SECURE_* middleware family. Enable SECURE_HSTS_SECONDS, SECURE_HSTS_INCLUDE_SUBDOMAINS, SECURE_HSTS_PRELOAD, SECURE_SSL_REDIRECT, SESSION_COOKIE_SECURE, CSRF_COOKIE_SECURE, SECURE_REFERRER_POLICY.
  • X_FRAME_OPTIONS = "DENY" unless you genuinely embed your app in an iframe.
  • ORM raw queries. Model.objects.raw(sql, params) is parameterized; .extra() and connection.cursor().execute(sql) need careful escaping. Never f-string user input into SQL.
  • Password hashing. Default is PBKDF2; django[argon2] is the recommended upgrade. bcrypt is acceptable. MD5PasswordHasher is for legacy import only.
  • Admin URL. Move /admin/ to a non-guessable path AND add IP allow-list / 2FA. Public admin URLs invite credential-stuffing.
  • File uploads. Validate content-type AND magic bytes; never trust the client filename. Use django-storages to push uploads off the app server.
  • CVE history. Subscribe to django-announce; LTS releases get same-day patches for high-severity issues.

Real-world recipes

Package-level patterns — settings layout, signal usage, custom managers, ASGI bootstrapping. The companion python/django.md covers model and view basics; the recipes here target the structural choices teams make once an app is past the tutorial stage.

python
# Recipe 1 — Layered settings module
# settings/__init__.py
import os
env = os.environ.get("DJANGO_ENV", "dev")
if env == "prod":   from .prod import *
elif env == "test": from .test import *
else:               from .dev import *

Output: DJANGO_ENV picks the right module at startup; each file imports from a base.py for shared keys.

python
# Recipe 2 — Custom manager with reusable querysets
class PublishedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(published=True)

class Article(models.Model):
    title = models.CharField(max_length=200)
    published = models.BooleanField(default=False)
    objects = models.Manager()
    published_articles = PublishedManager()

Output: Article.published_articles.all() returns only published rows; Article.objects.all() returns everything.

python
# Recipe 3 — Signal for "after user save" side effects
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model

@receiver(post_save, sender=get_user_model())
def create_profile(sender, instance, created, **kw):
    if created:
        Profile.objects.create(user=instance)

Output: new users automatically get a Profile row; receivers fire after every save (filter with created).

python
# Recipe 4 — Raw SQL with safe parameter binding
from django.db import connection

def top_authors(limit: int):
    with connection.cursor() as cur:
        cur.execute("SELECT author_id, COUNT(*) FROM blog_article "
                    "GROUP BY author_id ORDER BY 2 DESC LIMIT %s", [limit])
        return cur.fetchall()

Output: parameterized %s placeholder; never f-string the limit value.

python
# Recipe 5 — Async view + async ORM (Django 5+)
async def home(request):
    articles = [a async for a in Article.published_articles.all()[:10]]
    return JsonResponse({"articles": [a.title for a in articles]})

Output: native async iteration over a queryset; requires an ASGI server to actually use a single event loop.

Troubleshooting common errors

Error / SymptomLikely causeFix
DisallowedHost: Invalid HTTP_HOST headerALLOWED_HOSTS missing the request hostAdd the host to ALLOWED_HOSTS; do not use * in production.
OperationalError: FATAL: password authentication failedWrong DB creds or wrong DATABASES["default"]Verify DATABASE_URL; use django-environ to avoid quoting bugs.
django.db.utils.ProgrammingError: relation "..." does not existMigrations not appliedpython manage.py migrate; CI should run migrate --check for staleness.
ImproperlyConfigured: SECRET_KEY setting must not be emptySettings module not loaded or env var missingSet DJANGO_SETTINGS_MODULE; load .env before django.setup().
RuntimeError: SynchronousOnlyOperationCalling sync ORM from async defWrap in sync_to_async or use the new a* async ORM methods.
CSRF verification failed. Request aborted.Form missing {% csrf_token %} or AJAX missing headerAdd token; for AJAX include X-CSRFToken from the cookie.
TemplateDoesNotExistAPP_DIRS off or template dir missingAdd app to INSTALLED_APPS; ensure TEMPLATES[0]["APP_DIRS"] = True.
Migration conflicts detectedTwo branches added migrations at the same nodepython manage.py makemigrations --merge or rebase one branch's migration.
502/504 from gunicorn under load--timeout too short or workers blocked on slow queryRaise --timeout; profile slow queries; use gthread worker.
Static files 404 in productioncollectstatic not run or STATIC_ROOT not servedRun collectstatic; configure WhiteNoise or nginx for /static/.

See also