# Python Django 5+ with DRF — Cursor Rules You are an expert Python developer building web applications with Django 5+ and Django REST Framework, following Django best practices. ## Code Style - Use Python 3.11+ features where appropriate: type hints, `match` statements, `StrEnum`. - Type-annotate function signatures for public functions and methods. Use `django-stubs` for Django type support. - Use `snake_case` for functions, variables, and modules. `PascalCase` for classes. `UPPER_SNAKE_CASE` for settings. - Follow Django naming conventions: models are singular (`User`, `Article`), apps are plural or descriptive (`users`, `articles`). - Line length: 88 characters (Black default). Use Black for formatting, Ruff for linting. - Import order: stdlib, Django, third-party, local. Use `isort` with Django profile. - Prefer f-strings for string formatting. - Write docstrings for all models, views, and serializers explaining their purpose. ## Django Project Structure - One app per domain concept. Keep apps focused and loosely coupled. - Use `apps.py` to configure app metadata and signal connections. - Place URL patterns in each app's `urls.py`, include them in the root `urls.py` with a namespace. - Use `settings/` package for environment-specific configs: `base.py`, `development.py`, `production.py`, `testing.py`. - Store reusable utilities in a `core` or `common` app. ## Models - Every model gets a docstring explaining its purpose and relationships. - Use explicit `related_name` on all ForeignKey and ManyToManyField relationships. - Define `__str__` on every model — it must return a meaningful human-readable string. - Use `Meta` class for ordering, constraints, indexes, verbose names, and permissions. - Prefer `UUIDField` for public-facing primary keys. Keep auto-incrementing `id` for internal use. - Use `TimeStampedModel` base class with `created_at` and `updated_at` fields for all models. - Use Django's built-in field types. Prefer `CharField` with `max_length` over `TextField` when length is bounded. - Define choices as `TextChoices` or `IntegerChoices` enums on the model class. - Add database indexes on fields used in frequent queries: `db_index=True` or `Meta.indexes`. - Use `constraints` in Meta for database-level validation (UniqueConstraint, CheckConstraint). ## Views and Serializers (DRF) - Prefer `ModelViewSet` for full CRUD. Use `GenericAPIView` + mixins for partial CRUD. - Use `ModelSerializer` for standard serialization. Use `Serializer` for custom input/output shapes. - Define `read_only_fields` in serializer Meta. Never allow users to set `id`, `created_at`, `updated_at`. - Use separate serializers for create, update, list, and detail when field sets differ. - Override `get_queryset()` to scope queries to the current user or permissions. - Use `select_related` and `prefetch_related` in `get_queryset` to prevent N+1 queries. - Use `permission_classes` on every view. Default to `IsAuthenticated` — explicitly set `AllowAny` only when needed. - Use `@action` decorator for custom endpoints on viewsets: `@action(detail=True, methods=['post'])`. - Implement pagination: use `PageNumberPagination` or `CursorPagination` for large datasets. - Return consistent response shapes. Use DRF's built-in response formatting. ## URL Routing - Use DRF `DefaultRouter` for viewset URL registration. - Use `path()` over `re_path()` unless regex is genuinely needed. - Namespace all app URLs: `app_name = 'users'` and `path('users/', include('users.urls', namespace='users'))`. - Use `reverse()` or `reverse_lazy()` for URL generation. Never hardcode URL paths. - Keep URL patterns RESTful: `users/`, `users//`, `users//activate/`. ## ORM Best Practices - Use `QuerySet` methods for database operations. Never write raw SQL unless absolutely necessary. - Chain QuerySet methods for readability: `User.objects.filter(...).select_related(...).order_by(...)`. - Use `F()` expressions for database-level field references in queries and updates. - Use `Q()` objects for complex lookups (OR conditions, negations). - Use `annotate()` and `aggregate()` for computed fields and summaries. - Use `Subquery` and `OuterRef` instead of multiple queries for correlated lookups. - Avoid `QuerySet.all()` without pagination or limits — always scope your queries. - Use `bulk_create`, `bulk_update` for batch operations. Set `batch_size` for large datasets. - Use `transaction.atomic()` for operations that must succeed or fail together. ## Error Handling - Use DRF exception handling. Raise `ValidationError`, `NotFound`, `PermissionDenied` from `rest_framework.exceptions`. - Create custom exception classes for domain-specific errors. Register them with `EXCEPTION_HANDLER` in settings. - Validate at the serializer level (field validation, object validation) and the model level (`clean()` method). - Log all unhandled exceptions with request context. Use `structlog` or Django's logging configuration. - Return consistent error response format: `{"detail": "message"}` or `{"field_name": ["error messages"]}`. - Never expose internal error details (tracebacks, SQL queries) in API responses. ## Authentication and Permissions - Use `django-rest-framework-simplejwt` for JWT authentication, or session auth for browser-based apps. - Create custom permission classes for business logic authorization. Place them in `permissions.py` per app. - Use object-level permissions when access depends on the specific resource (e.g., owner-only access). - Implement role-based access with Django groups or a custom permission model. ## Testing - Use `pytest-django` with `pytest`. Configure in `pytest.ini` or `pyproject.toml`. - Use `APIClient` for DRF endpoint tests. Test each endpoint: success, validation, auth, permissions, edge cases. - Use `baker` (model-bakery) or `factory_boy` for test data creation. Never use fixtures for dynamic test data. - Use `@pytest.mark.django_db` for tests that need database access. - Test model methods, validators, and signals in isolation. - Place tests in `tests/` directory per app: `tests/test_views.py`, `tests/test_models.py`, `tests/test_serializers.py`. - Use `override_settings` decorator for tests that need different settings. ## File Structure ``` project/ config/ settings/ base.py development.py production.py urls.py wsgi.py asgi.py apps/ core/ — Shared models, utils, base classes models.py — TimeStampedModel, etc. users/ models.py serializers.py views.py urls.py permissions.py signals.py admin.py tests/ test_views.py test_models.py articles/ models.py serializers.py views.py urls.py filters.py tests/ manage.py requirements/ base.txt development.txt production.txt ``` ## Performance - Always use `select_related` (ForeignKey, OneToOne) and `prefetch_related` (ManyToMany, reverse FK) in querysets. - Use Django Debug Toolbar in development to catch N+1 queries. - Cache expensive computations with Django's cache framework. Use `@cache_page` for view caching. - Use database indexes for frequently filtered and ordered fields. - Use `defer()` and `only()` to limit fields loaded from the database when you don't need all columns. - Paginate all list endpoints. Never return unbounded querysets. ## Security - Keep `SECRET_KEY` in environment variables. Never commit it to version control. - Set `ALLOWED_HOSTS` explicitly in production. Never use `['*']`. - Use Django's CSRF protection. Do not disable it for API endpoints served to browsers. - Enable security middleware: `SecurityMiddleware`, HSTS, content type sniffing protection. - Validate and sanitize all user input through serializers. Escape output in templates. - Use `SECURE_SSL_REDIRECT = True` in production. - Regularly update Django and all dependencies for security patches.