Skip to content
Skill · Claude CodeCLAUDE.mdCoding

Django Project Instructions

CLAUDE.md for Django projects: app structure, ORM query rules, migration workflow, layered settings, and pytest-django conventions agents must follow before touching models.

Use when: Use in a Django 5.x codebase so agents handle migrations safely, keep business logic out of views, and avoid N+1 queries when writing or reviewing ORM code.

@libraryNewcomer
0 upvotes0 forks0 comments

The skill file

Claude Code · CLAUDE.md
CLAUDE.md3456 chars
# Project Instructions — Django ## Commands ```bash uv run python manage.py runserver # dev server → http://localhost:8000 uv run pytest # full test suite (pytest-django, not manage.py test) uv run pytest apps/orders -x # focused run while iterating uv run python manage.py makemigrations # after any model change uv run python manage.py migrate # apply locally uv run python manage.py makemigrations --check --dry-run # CI gate: fails if migrations are missing uv run ruff format . && uv run ruff check --fix . ``` ## App structure Apps live under `apps/` and are small and domain-focused (`apps/orders`, `apps/accounts`). Standard layout per app: ``` apps/orders/ models.py # schema only: fields, Meta, constraints, simple properties services.py # business logic — all writes go through functions here selectors.py # read queries used by views/tasks views.py / api.py admin.py migrations/ tests/ ``` - **Views stay thin.** A view parses input, calls one service/selector function, returns a response. If a view grows conditional business logic, move it to `services.py`. - Cross-app imports go through the other app's `services.py`/`selectors.py`, never its models' managers directly. ## ORM rules - Every queryset that touches related objects in a loop uses `select_related` (FK/one-to-one) or `prefetch_related` (many). When you add a template loop or serializer over a queryset, check for N+1 explicitly. - Use `.exists()` instead of `len()`/truthiness for existence checks, `.count()` instead of `len(qs)`, `.update()`/`.bulk_create()` for bulk writes. - Wrap multi-step writes in `transaction.atomic()`; trigger side effects (emails, webhooks) via `transaction.on_commit`. - Enforce invariants in the database: `UniqueConstraint`/`CheckConstraint` in `Meta.constraints`, not just `clean()` methods. - Custom managers/querysets for reusable filters: `Order.objects.unpaid()` rather than repeating `.filter(status="unpaid")`. ## Migrations - Never edit an applied migration. To change one that has shipped, add a new migration. - One logical change per migration; name it: `makemigrations orders -n add_refund_status`. - Data migrations use `apps.get_model("orders", "Order")` — never import models directly into a migration. - Adding a non-nullable field to a populated table happens in two deploys: (1) add nullable + backfill, (2) make it non-nullable. Flag this in your summary whenever it applies. - After model changes, run the `--check --dry-run` command above to confirm nothing is missing. ## Settings ``` config/settings/base.py # everything shared config/settings/local.py # dev: DEBUG=True, console email config/settings/production.py ``` - Secrets and per-environment values come from environment variables via `django-environ` — never hardcode them in any settings file. - New settings go in `base.py` with a safe default; override per environment only when values genuinely differ. ## Tests (pytest-django) - Plain test functions with the `db` fixture / `@pytest.mark.django_db`; no `TestCase` classes in new code. - Build objects with `factory_boy` factories in `apps/<app>/tests/factories.py` — never fixtures-as-JSON. - Test services and selectors directly; test views only for status codes, permissions, and serialization shape. - Assert query efficiency on hot paths with `django_assert_num_queries`.

Install

drop into your repo

Save this to your project or home directory so Claude Code can load it.

path./CLAUDE.md
Discussion

What people are saying

Forks

0 forks of this skill
Loading forks…