Instruction file imported from Doumajnik/template (
.github/instructions/django.instructions.md). Copyright stays with the author.
Django Conventions
- Always set
on_deleteexplicitly onForeignKeyandOneToOneField— useCASCADEfor owned children,PROTECTfor referenced lookups,SET_NULL(withnull=True) for optional associations. Never useon_delete=models.DO_NOTHING - Define a
Metaclass on every model with at leastordering,verbose_name, andverbose_name_plural. AddconstraintsandindexesinMetainstead of field-leveldb_index=Truefor compound indexes - Use
select_related()forForeignKey/OneToOneFieldjoins andprefetch_related()for reverse relations andManyToManyField. Profile queries withdjango-debug-toolbarorassertNumQueriesin tests to catch N+1 - Use
F()expressions for database-level field references in updates and annotations — never read a field into Python just to write it back (e.g.,Model.objects.filter(...).update(count=F('count') + 1)) - Use
Q()objects for complex lookups withOR,NOT, or nested boolean logic. Combine with&,|,~operators — never use raw SQL for conditions expressible with the ORM - Use
.values()or.values_list()when you only need specific columns — avoid loading full model instances for read-only aggregate or export queries - Prefer class-based views (
ListView,DetailView,CreateView,UpdateView) for standard CRUD. Use function-based views only for non-standard flows or when CBV mixins become convoluted - Apply
LoginRequiredMixinorPermissionRequiredMixinas the first parent in CBV inheritance order. For FBVs use@login_requiredand@permission_requireddecorators. Never checkrequest.user.is_authenticatedmanually in views that have a mixin/decorator available - Define URL patterns in per-app
urls.pymodules and include them in the rooturlconfwithapp_namefor namespacing. Usereverse()or{% url %}with namespace — never hardcode URL paths - Write custom middleware as a function-based middleware (ASGI/WSGI compatible) or class with
__init__/__call__. Keep middleware thin — delegate logic to services. Order middleware carefully: security middleware first, auth before permission checks - Use signals sparingly — only for decoupled cross-app notifications (e.g.,
post_savefor audit logging). Never use signals for same-app business logic; call service functions directly instead - Use Django REST Framework serializers for API input validation and output shaping. Use
ModelSerializerfor standard CRUD,Serializerfor custom shapes. Always setfieldsexplicitly — never usefields = '__all__' - Validate at the model level with
clean()and field validators so validation runs on both form and API paths. RaiseValidationErrorwith a message dict keyed by field name - Always review auto-generated migrations before committing. Never hand-edit auto-migrations — create a separate manual migration with
RunPythonorRunSQLfor data migrations. Squash migrations periodically in long-lived apps - Register every model in
admin.pywith at leastlist_display,search_fields, andlist_filter. Usereadonly_fieldsfor computed/audit fields. Overrideget_querysetto addselect_relatedfor admin list views - Use Django's template engine only for server-rendered pages. Avoid complex logic in templates — move it to template tags, filters, or view context. Never call methods with side effects from templates
- Rely on Django's built-in CSRF protection — never use
@csrf_exemptunless the endpoint is a webhook with its own signature verification. Use{% csrf_token %}in all HTML forms - Use Django's ORM parameterized queries exclusively. Never interpolate user input into raw SQL. If
raw()orextra()is unavoidable, use params — never f-strings or.format() - Structure settings with
django-environfor environment variable parsing. Split intobase.py,development.py,production.py, andtesting.pythat import from base. Never commit secrets to settings files - Use Django's cache framework (
django.core.cache) with a backend like Redis. Cache expensive querysets and computed values. Use@cache_pagefor full-page caching andcache.get_or_set()for fragment caching. Always set explicit timeouts - Define Celery tasks in per-app
tasks.pyfiles. Use@shared_taskdecorator. Setacks_late=Trueandreject_on_worker_lost=Truefor critical tasks. Always settime_limitandsoft_time_limiton tasks to prevent runaway workers - Use
django.test.TestCasefor tests that need database access andSimpleTestCasefor tests that don't. Use DRF'sAPITestCasefor API endpoint tests. Preferfactory_boyover fixtures for test data setup - Define custom managers on models for reusable query logic (e.g.,
PublishedManagerwith.get_queryset().filter(status='published')). Attach asobjectsor a secondary manager — keep the default manager unfiltered - Use
FileFieldorImageFieldwith a customupload_tocallable for organized storage. Validate file type and size in the model'sclean()method. Serve user uploads through a CDN or dedicated media server — never from the app server in production - Use Django's
Paginatorfor server-rendered pages and DRF'sPageNumberPaginationorCursorPaginationfor APIs. Always paginate list endpoints — never return unbounded querysets - Use
transaction.atomic()as a context manager for operations that must succeed or fail together. Avoid nestingatomic()blocks — usesavepoint=Falseif nesting is unavoidable - Use
django.utils.timezone.now()instead ofdatetime.now()ordatetime.utcnow(). Store all timestamps in UTC. SetUSE_TZ = Truein settings — never disable timezone support - Use
CharFieldwithchoicesfor small fixed sets, or a separate model withForeignKeyfor large/dynamic option sets. In Django 5+, useGeneratedFieldfor database-level computed columns instead of@propertyfor frequently queried derived values - Use
unique_togetherorUniqueConstraintinMeta.constraintsfor composite uniqueness. PreferCheckConstraintfor database-level business rule enforcement over application-only validation - Use
django.contrib.auth.get_user_model()to reference the user model — never importUserdirectly. Define a custom user model extendingAbstractUserorAbstractBaseUserat project start, even if the default fields suffice - For Django 5+ async views, use
async defview functions withasync foron querysets andawaiton ORM calls (aget,afilter,acreate, etc.). Never mix sync ORM calls inside async views — usesync_to_asynconly as a last resort - Use
manage.py check --deploybefore every production deployment to catch common security misconfigurations. EnsureSECURE_SSL_REDIRECT,SECURE_HSTS_SECONDS,SESSION_COOKIE_SECURE, andCSRF_COOKIE_SECUREare all enabled in production settings - Define
__str__on every model returning a human-readable representation. Defineget_absolute_url()on models that have a detail page. Use these consistently in admin, templates, and logs - Use
django.core.mail.send_mailwith a configurable backend — never call SMTP directly. Usedjango-anymailfor production email services. Always send email asynchronously via Celery in production - Use
LogEntryordjango-auditlogfor tracking model changes. Store the user, timestamp, and diff of changed fields. Never rely on signals alone for audit trails — signals can be bypassed by bulk operations