Django + DRF Rules
Django REST Framework conventions: viewsets, serializers, permissions.
# CLAUDE.md — Django + DRF
## Apps
- One Django app per bounded context. Don't make a single `core` app that owns everything.
- App layout:
```
myapp/
models.py
serializers.py
views.py # ViewSets / APIViews
urls.py
permissions.py
services.py # business logic
selectors.py # read-only queries
tests/
```
- Business logic lives in `services.py` (writes) and `selectors.py` (reads). Views call services. Models stay thin.
## Serializers
- One serializer per output shape. Don't reuse the same serializer for list and detail when fields differ — add a `ListSerializer` and `DetailSerializer`.
- Validate at the serializer (`validate_<field>`, `validate`). Don't validate inside views.
- Use `source=` to map field names; don't rename in the model just to please an API contract.
- For nested writes, override `create`/`update` explicitly. Don't rely on `WritableNestedSerializer` magic.
## ViewSets
- `ModelViewSet` for full CRUD. `ReadOnlyModelViewSet` for read-only resources. Don't use generic mixins by hand when a ViewSet does it.
- Override `get_queryset` to scope by user/tenant — the base `queryset` attribute should be the unscoped default.
- Override `get_serializer_class` to switch between list/detail/write serializers.
- Custom actions with `@action(detail=True/False, methods=[...])` — never overload PATCH for "do this thing".
## Permissions
- Default to `[IsAuthenticated]` globally in `REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES']`.
- Per-view permissions are subclasses of `BasePermission`. Combine with `&`, `|`, `~`.
- Object-level checks go in `has_object_permission`. Don't duplicate them in `get_queryset` and pretend it's enough — it isn't for direct lookups.
## Pagination & filtering
- Set `DEFAULT_PAGINATION_CLASS` and `PAGE_SIZE`. Never return unpaginated lists from production endpoints.
- Use `django-filter` for query-string filters. Don't write `if request.GET.get(...)` chains.
- For sort, use DRF's `OrderingFilter` with an explicit `ordering_fields` allowlist.
## Errors
- Raise DRF exceptions (`NotFound`, `PermissionDenied`, `ValidationError`). Don't return `Response({'error': ...}, status=...)` from view code.
- Custom exceptions inherit from `APIException` with `status_code` and `default_detail`.
## Don't
- Don't put business logic in the serializer. Serializers shape and validate; services act.
- Don't use `select_related` / `prefetch_related` only on the detail endpoint. Profile the list endpoint.
- Don't expose internal field names (`is_deleted`, `internal_notes`) without filtering with serializer `fields` or `exclude`.
- Don't disable CSRF on session-authenticated endpoints.
Other Python templates
Modern Python Rules
Type hints, ruff, black, uv, and pytest — opinionated Python defaults.
Python Data Science (pandas + numpy)
Notebook discipline, vectorization, and reproducible analysis with pandas.
Python Clean Architecture
Layered architecture with use-cases, repositories, and dependency inversion.
Python asyncio Patterns
asyncio fundamentals: tasks, gather, cancellation, and structured concurrency.
Python CLI Tools (Typer)
Build polished CLIs with Typer, Rich output, and clean argument parsing.