---
paths:
  - "**/models.py"
  - "**/models/*.py"
  - "**/migrations/*.py"
  - "**/services.py"
---

# Django models, migrations and queries

- After changing a model, run `python manage.py makemigrations <app>` and read the generated file. Never hand-edit an applied migration; write a new one.
- Data migrations use `RunPython(forward, backward)` with `apps.get_model(...)`, never direct model imports.
- Adding a non-null column to a big table: add it nullable or with `db_default`, backfill in batches, then tighten.
- Every `ForeignKey` sets `on_delete` deliberately and a `related_name`.
- Business invariants as DB constraints in `Meta.constraints` (`UniqueConstraint`, `CheckConstraint`), not only in Python.
- Index fields used in filters/order (`Meta.indexes`), and say why in the PR.
- Query rules:
  - `select_related` for FK/one-to-one, `prefetch_related` for reverse/M2M.
  - `F()` for atomic updates (`stock=F("stock") - 1`), `select_for_update()` inside `transaction.atomic()` for read-then-write.
  - `bulk_create`/`bulk_update` for batches; `.iterator()` for large scans.
  - `exists()` instead of `count() > 0`.
- `__str__` on every model; `get_absolute_url` where there's a detail page.
- Don't put request/HTTP logic in models.

Check with `python manage.py makemigrations --check --dry-run` and the test suite.
