django-best-practices
Installation
SKILL.md
Django Best Practices
A senior Django developer's knowledge base covering 27 topics — from ORM queries to deployment. This skill provides wrong vs correct code examples and architectural guidance for building production-grade Django applications.
When to use this skill
- Creating or modifying Django models, fields, or relations
- Writing views (FBV, CBV, or DRF ViewSets)
- Building or updating DRF serializers and API endpoints
- Writing ORM queries, fixing N+1 problems, or optimizing performance
- Creating or reviewing migrations
- Configuring Django settings, middleware, or URL routing
- Implementing authentication, permissions, or session management
- Setting up caching (Redis, Memcached, per-view, fragment)
- Writing or reviewing tests (Django TestCase, pytest, factories)
- Working with Django signals, forms, templates, or template tags
- Configuring static/media files, file uploads, or storage backends
- Setting up Celery tasks, periodic tasks, or background jobs
- Deploying Django (Gunicorn, Nginx, Docker, CI/CD)
- Working with Django Channels or WebSockets
- Implementing i18n/l10n or timezone support
- Reviewing code for security issues (CSRF, XSS, SQL injection)
- Designing app architecture, service layers, or project structure
Workflow
When this skill is activated, follow these steps:
- Identify the topic — Determine which area of Django the task involves (models, views, queries, etc.)
- Read the relevant reference file — Consult the reference table below and read the appropriate file before writing any code
- Apply the correct patterns — Follow the "Correct" patterns from the reference file, avoid the "Wrong" anti-patterns
- Check for common mistakes — Review the "Why" explanations to understand the reasoning behind each pattern
- Cross-reference related topics — If the task spans multiple areas (e.g., views + queries + templates), read all relevant reference files
Always read the relevant reference file before writing code for that topic.
Key Principles
Project Structure
- Separate config from apps. Use
config/settings/with base, local, and production files. - Keep apps small and focused (3-8 models per app). Split when an app exceeds 15 models.
- Always set
AUTH_USER_MODELbefore the first migration. - Reference users via
settings.AUTH_USER_MODEL, neverauth.Userdirectly.
Models & ORM
- Use
DecimalFieldfor money,BooleanFieldfor flags,EmailFieldfor emails. - Always set explicit
related_nameon ForeignKey and OneToOneField. - Use
select_relatedfor ForeignKey/OneToOne,prefetch_relatedfor ManyToMany/reverse FK. - Use
F()expressions for atomic updates to avoid race conditions. - Use
Exists()instead of.count() > 0for existence checks. - Use
bulk_createandbulk_updatefor batch operations. - Wrap multi-step writes in
transaction.atomic().
Queries
- Never filter in Python when the database can do it.
- Use
Qobjects for OR/NOT queries. - Use
annotatewithSubqueryinstead of N+1 loops. - Always parameterize raw SQL — never use f-strings.
- Use
.values_list()when you don't need full model instances. - Use
.exists()instead of.count() > 0. - Use
.iterator()for large querysets.
Views
- Use FBVs for simple one-off views, CBVs for CRUD with generics.
- Always use
LoginRequiredMixinor@login_requiredfor protected views. - Override
get_queryset()to enforce ownership in UpdateView/DeleteView. - Use
get_object_or_404in views,.first()when absence is expected.
Forms & Validation
- Always use explicit
fieldsin ModelForm — neverexcludeor__all__. - Use
clean_<field>()for single-field validation,clean()for cross-field. - Use Django's built-in validators and write custom ones for domain rules.
Security
- Never disable CSRF except for external webhooks with their own auth.
- Never use
mark_safe()or|safeon user input — useformat_html(). - Never use f-strings in raw SQL — always parameterize.
- Use Argon2 for password hashing, PBKDF2 as fallback.
- Set
SECURE_SSL_REDIRECT,SECURE_HSTS_*, and cookie security flags in production. - Run
manage.py check --deploybefore every deployment.
Admin
- Always configure
list_display,list_filter, andsearch_fields. - Use
list_select_relatedto prevent N+1 queries in list views. - Use
readonly_fieldsfor computed/automatic values. - Override permission methods to restrict what staff can do.
Templates
- Use template inheritance with
base.htmland{% block %}tags. - Always use
{% url %}and{% static %}— never hardcode paths. - Use
{% empty %}in for loops and{% with %}for expensive lookups. - Never use
{% autoescape off %}or|safeon user content.
Migrations
- Make small, focused migrations with descriptive names.
- Always provide reverse operations for custom/data migrations.
- Use
apps.get_model()in data migrations, never direct model imports. - Multi-step approach for column removal: make nullable → deploy → remove.
- Use
--planto preview migrations before running in production.
Testing
- Use
SimpleTestCasefor no-DB tests,TestCasefor DB tests. - Use
setUpTestDatafor class-level test data (faster thansetUp). - Use factory_boy instead of JSON fixtures.
- Mock external services (SMS, payments, APIs).
- Use
@override_settingsand Django'slocmememail backend for testing. - Aim for 80%+ coverage on business logic.
DRF
- Always use explicit
fieldsin serializers — never__all__. - Use separate read/write serializers for nested data.
- Set
IsAuthenticatedas the global default permission. - Always paginate list endpoints.
- Use
django-filterfor declarative filtering. - Optimize
get_queryset()withselect_related/prefetch_related.
Signals
- Import signals in
AppConfig.ready(), never at module level. - Use
dispatch_uidto prevent duplicate connections. - Prefer explicit method calls over signals for tightly coupled logic.
- Use signals only for decoupled cross-app communication.
Caching
- Use
DummyCachein development, Redis in production. - Use namespaced cache keys with timeouts.
- Invalidate targeted keys, never
cache.clear(). - Cache at the most granular level that makes sense.
Deployment
- Never use
runserverin production — use Gunicorn or Uvicorn. - Use multi-stage Docker builds.
- Store secrets in environment variables, never in code.
- Use zero-downtime deployment with Gunicorn HUP signal.
- Always have a health check endpoint.
Background Tasks
- Pass IDs to tasks, never model instances.
- Always implement retry logic with exponential backoff.
- Make tasks idempotent — safe to run more than once.
- Use
@shared_taskinstead of importing the Celery app directly.
Reference Files
Read the relevant reference file before writing code for that topic.
| Topic | File | When to read |
|---|---|---|
| Project structure & settings | references/core.md |
Setting up a Django project, configuring settings, WSGI/ASGI, management commands |
| Model design | references/models.md |
Creating or modifying models, fields, relations, Meta options, managers, abstract/proxy models |
| ORM queries | references/queries.md |
Writing queries, fixing N+1, using Q/F objects, aggregation, subqueries, transactions |
| Migrations | references/migrations.md |
Creating migrations, data migrations, squashing, zero-downtime schema changes |
| Django Admin | references/admin.md |
Configuring admin, inline models, custom actions, fieldsets, admin security/performance |
| Views | references/views.md |
Writing FBVs or CBVs, generic views, mixins, choosing between FBV and CBV |
| URL routing | references/urls.md |
Configuring URLs, namespaces, path converters, reverse/reverse_lazy |
| Templates | references/templates.md |
Template inheritance, tags, filters, custom template tags, context processors, security |
| Forms | references/forms.md |
Django forms, ModelForms, validation, custom validators, formsets, file upload security |
| Authentication & sessions | references/auth.md |
User models, auth backends, login/logout, password reset, permissions, groups, sessions, cookies |
| Middleware | references/middleware.md |
Middleware order, custom middleware, exception handling, async middleware |
| Static & media files | references/static-media.md |
Static/media configuration, collectstatic, WhiteNoise, S3/CDN, file uploads, storage backends |
| Security | references/security.md |
CSRF, XSS, SQL injection, clickjacking, password hashing, HTTPS, SECRET_KEY, security checks |
| Signals | references/signals.md |
pre/post_save, pre/post_delete, m2m_changed, custom signals, when to avoid signals |
| Caching | references/caching.md |
Cache backends, Redis, per-view/fragment/low-level caching, invalidation strategies |
| Internationalization | references/i18n.md |
i18n settings, gettext/gettext_lazy, translation tags, timezone support, locale structure |
| Testing | references/testing.md |
TestCase types, Client/RequestFactory, fixtures, pytest-django, factory_boy, mocking, coverage |
| Django REST Framework | references/drf.md |
Serializers, viewsets, routers, authentication, permissions, throttling, pagination, filtering |
| Background tasks | references/celery.md |
Celery setup, task definition, retries, queues, periodic tasks, Django-Q, Huey, idempotency |
| Deployment & performance | references/deployment.md |
Gunicorn, Nginx, Docker, CI/CD, zero-downtime deploys, query optimization, indexing, async views |
| Django Channels | references/channels.md |
ASGI setup, WebSocket consumers, channel layers, group messaging, WS authentication, SSE |
| Django ecosystem | references/ecosystem.md |
DRF, django-filter, allauth, debug toolbar, storages, guardian, import-export, unfold, django-redis |
| Architecture patterns | references/architecture.md |
Custom fields, multi-DB, database routers, Jinja2, ORM internals, MTV, service layer, DDD, SOLID |