Python Django Cheat Sheet
Covers Django project and app setup, models, migrations, views, URL routing, and common ORM query patterns for building web applications.
Project & App Setup
Scaffold a Django project and run the dev server.
pip install django # Install Djangodjango-admin startproject mysite . # Create project in current dirpython manage.py startapp blog # Create an apppython manage.py runserver # Run dev server (localhost:8000)python manage.py runserver 0.0.0.0:8080 # Run on custom host/port
Models
Define database tables as Python classes.
from django.db import modelsclass Post(models.Model): title = models.CharField(max_length=200) body = models.TextField() published = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) author = models.ForeignKey( "auth.User", on_delete=models.CASCADE, related_name="posts" ) def __str__(self): return self.title
Migrations
Generate and apply schema changes.
python manage.py makemigrations # Create migration files from model changespython manage.py migrate # Apply migrations to the databasepython manage.py sqlmigrate blog 0001 # Preview SQL for a migrationpython manage.py showmigrations # List migrations and their applied status
Views & URL Routing
Wire URLs to view functions and query the database.
# views.pyfrom django.shortcuts import render, get_object_or_404from .models import Postdef post_list(request): posts = Post.objects.filter(published=True).order_by("-created_at") return render(request, "blog/list.html", {"posts": posts})def post_detail(request, pk): post = get_object_or_404(Post, pk=pk) return render(request, "blog/detail.html", {"post": post})# urls.pyfrom django.urls import pathfrom . import viewsurlpatterns = [ path("", views.post_list, name="post_list"), path("<int:pk>/", views.post_detail, name="post_detail"),]
Common ORM Queries
Frequently used QuerySet methods.
- Model.objects.all()- Return a QuerySet of every row
- Model.objects.get(pk=1)- Fetch a single object; raises DoesNotExist if none match
- Model.objects.filter(field=value)- Return a QuerySet matching a condition
- Model.objects.exclude(field=value)- Return objects that don't match a condition
- .order_by('-created_at')- Sort results, prefix with '-' for descending order
- .select_related('author')- Eager-load a ForeignKey in the same SQL query via JOIN
- .prefetch_related('tags')- Eager-load a many-to-many/reverse-FK with a separate query
- Model.objects.create(**kwargs)- Create and save a new row in a single call
Class-Based Views & Generic Views
Replace repetitive function views with Django's built-in generic CBVs.
from django.views.generic import ListView, DetailView, CreateViewfrom django.urls import reverse_lazyfrom .models import Postclass PostListView(ListView): model = Post template_name = "blog/list.html" context_object_name = "posts" paginate_by = 20 def get_queryset(self): return Post.objects.filter(published=True).select_related("author")class PostCreateView(CreateView): model = Post fields = ["title", "body"] success_url = reverse_lazy("post_list") def form_valid(self, form): form.instance.author = self.request.user return super().form_valid(form)
Custom Managers & QuerySets
Encapsulate reusable, chainable query logic instead of repeating filters everywhere.
from django.db import modelsclass PostQuerySet(models.QuerySet): def published(self): return self.filter(published=True) def by_author(self, user): return self.filter(author=user)class PostManager(models.Manager): def get_queryset(self): return PostQuerySet(self.model, using=self._db) def published(self): return self.get_queryset().published()class Post(models.Model): # ...fields... objects = PostManager()# Usage: Post.objects.published().by_author(request.user)
Signals & Custom Middleware
React to model lifecycle events and hook into every request/response cycle.
from django.db.models.signals import post_savefrom django.dispatch import receiverfrom .models import Post@receiver(post_save, sender=Post)def notify_on_publish(sender, instance, created, **kwargs): if created and instance.published: send_notification(instance)# middleware.pyclass RequestTimingMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): import time start = time.monotonic() response = self.get_response(request) response["X-Request-Duration-Ms"] = str(int((time.monotonic() - start) * 1000)) return response# settings.py: add "myapp.middleware.RequestTimingMiddleware" to MIDDLEWARE
Transactions, select_for_update & atomic()
Guarantee consistency for multi-step writes and avoid race conditions under concurrent load.
from django.db import transaction@transaction.atomicdef transfer_credits(from_account_id, to_account_id, amount): from .models import Account from_acc = Account.objects.select_for_update().get(pk=from_account_id) to_acc = Account.objects.select_for_update().get(pk=to_account_id) if from_acc.balance < amount: raise ValueError("Insufficient balance") from_acc.balance -= amount to_acc.balance += amount from_acc.save() to_acc.save()# transaction.on_commit(lambda: send_email(...)) # Defer side effects until commit succeeds
Testing & Auth/Permissions Essentials
Tools for writing reliable tests and locking down views.
- TestCase- Wraps each test in a transaction that's rolled back, so tests stay isolated and fast
- Client()- Simulates HTTP requests against your app without running a real server
- @login_required- Decorator that redirects anonymous users to LOGIN_URL
- PermissionRequiredMixin- CBV mixin enforcing a Django permission before dispatching the view
- factory_boy- Third-party library for generating realistic test model instances (alternative to fixtures)
- django.test.override_settings- Context manager/decorator to temporarily change settings within a test
- assertNumQueries- TestCase helper asserting the exact query count, useful for catching N+1 regressions
Use select_related() for ForeignKey/OneToOne fields and prefetch_related() for ManyToMany/reverse-FK fields to avoid the N+1 query problem — django-debug-toolbar makes it easy to spot in development.