LearnThatStack Ace your next interview

Django.
Cheat sheet.

Quick reference for Django - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

Backend Development 16-section reference ~12 min read

Summary

Django is a high-level Python web framework that follows the MVT (Model-View-Template) architecture pattern. This cheatsheet covers essential Django concepts including models and ORM, views, templates, forms, authentication, middleware, REST API development, security, performance optimization, and testing. Key features include "batteries included" philosophy, automatic admin interface, robust ORM, and built-in security measures.

1. Django Basics

What is Django?

  • High-level Python web framework following MVT (Model-View-Template) architecture
  • "Batteries included" philosophy - provides ORM, admin panel, authentication, etc.
  • Follows DRY (Don't Repeat Yourself) principle

Project Structure

myproject/
├── manage.py           # Command-line utility
├── myproject/         # Project package
│   ├── __init__.py
│   ├── settings.py    # Project settings
│   ├── urls.py       # Root URL configuration
│   └── wsgi.py       # WSGI entry point
└── myapp/            # App directory
    ├── models.py     # Database models
    ├── views.py      # View functions/classes
    ├── urls.py       # App URL patterns
    ├── admin.py      # Admin interface
    └── tests.py      # Tests

Basic Commands

# Create project
django-admin startproject myproject

# Create app
python manage.py startapp myapp

# Run development server
python manage.py runserver

# Create/apply migrations
python manage.py makemigrations
python manage.py migrate

# Create superuser
python manage.py createsuperuser

# Collect static files
python manage.py collectstatic

2. Models & ORM

Model Definition

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        db_table = 'authors'
        ordering = ['-created_at']
    
    def __str__(self):
        return self.name

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
    published_date = models.DateField()
    price = models.DecimalField(max_digits=6, decimal_places=2)
    is_available = models.BooleanField(default=True)

Field Types

  • CharField, TextField, EmailField, URLField
  • IntegerField, FloatField, DecimalField
  • BooleanField, DateField, DateTimeField
  • FileField, ImageField
  • ForeignKey, ManyToManyField, OneToOneField

Field Options

field = models.CharField(
    max_length=100,
    null=True,          # Database NULL allowed
    blank=True,         # Form validation allows empty
    default='value',    # Default value
    unique=True,        # Unique constraint
    db_index=True,      # Database index
    choices=CHOICES,    # Limit values
    validators=[...]    # Custom validators
)

Relationships

# One-to-Many
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# on_delete options: CASCADE, PROTECT, SET_NULL, SET_DEFAULT

# Many-to-Many
tags = models.ManyToManyField(Tag, related_name='books')

# One-to-One
profile = models.OneToOneField(UserProfile, on_delete=models.CASCADE)

QuerySet API

# Basic queries
Book.objects.all()
Book.objects.filter(price__gte=20)
Book.objects.exclude(is_available=False)
Book.objects.get(id=1)  # Raises DoesNotExist if not found

# Chaining
Book.objects.filter(price__gte=20).exclude(author__name='John')

# Lookups
Book.objects.filter(
    title__icontains='django',      # Case-insensitive contains
    price__gte=20,                  # Greater than or equal
    published_date__year=2023,      # Date part extraction
    author__name__startswith='J'    # Relationship lookup
)

# Aggregation
from django.db.models import Count, Avg, Max, Min, Sum
Book.objects.aggregate(avg_price=Avg('price'))
Author.objects.annotate(book_count=Count('books'))

# Q objects for complex queries
from django.db.models import Q
Book.objects.filter(Q(price__gte=20) | Q(title__icontains='python'))

# F expressions for field references
from django.db.models import F
Book.objects.filter(price__gt=F('discount_price') * 1.2)

# select_related (for ForeignKey) & prefetch_related (for ManyToMany)
Book.objects.select_related('author').all()  # Reduces queries
Book.objects.prefetch_related('tags').all()

# Common methods
.exists()
.count()
.first()
.last()
.order_by('-created_at')
.distinct()
.values('title', 'price')  # Returns dict
.values_list('title', flat=True)  # Returns list

Model Methods

class Book(models.Model):
    # ... fields ...
    
    def save(self, *args, **kwargs):
        # Custom save logic
        self.title = self.title.upper()
        super().save(*args, **kwargs)
    
    def delete(self, *args, **kwargs):
        # Custom delete logic
        super().delete(*args, **kwargs)
    
    @property
    def discounted_price(self):
        return self.price * 0.9

3. Views

Function-Based Views (FBV)

from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse, JsonResponse
from django.contrib.auth.decorators import login_required

def book_list(request):
    books = Book.objects.all()
    return render(request, 'books/list.html', {'books': books})

@login_required
def book_detail(request, pk):
    book = get_object_or_404(Book, pk=pk)
    return render(request, 'books/detail.html', {'book': book})

def book_create(request):
    if request.method == 'POST':
        # Process form data
        return redirect('book_list')
    return render(request, 'books/create.html')

Class-Based Views (CBV)

from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy

class BookListView(ListView):
    model = Book
    template_name = 'books/list.html'
    context_object_name = 'books'
    paginate_by = 10
    
    def get_queryset(self):
        return Book.objects.filter(is_available=True)

class BookDetailView(LoginRequiredMixin, DetailView):
    model = Book
    template_name = 'books/detail.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['related_books'] = Book.objects.filter(author=self.object.author)
        return context

class BookCreateView(CreateView):
    model = Book
    fields = ['title', 'author', 'price']
    success_url = reverse_lazy('book_list')
    
    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)

View Decorators & Mixins

# Decorators for FBV
@login_required
@require_http_methods(['GET', 'POST'])
@cache_page(60 * 15)
@csrf_exempt

# Mixins for CBV
LoginRequiredMixin
PermissionRequiredMixin
UserPassesTestMixin

4. URLs

URL Configuration

# project/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', include('books.urls', namespace='books')),
    path('api/', include('api.urls')),
]

# app/urls.py
from django.urls import path
from . import views

app_name = 'books'
urlpatterns = [
    path('', views.BookListView.as_view(), name='list'),
    path('<int:pk>/', views.BookDetailView.as_view(), name='detail'),
    path('create/', views.BookCreateView.as_view(), name='create'),
    path('<slug:slug>/', views.book_by_slug, name='by_slug'),
]

URL Patterns

# Path converters
path('article/<int:pk>/', ...)      # Matches integer
path('post/<slug:slug>/', ...)      # Matches slug
path('page/<path:path>/', ...)      # Matches any path
path('user/<str:username>/', ...)   # Matches string
path('item/<uuid:uuid>/', ...)      # Matches UUID

# Regular expressions (re_path)
from django.urls import re_path
re_path(r'^article/(?P<year>[0-9]{4})/$', ...)

Reverse URLs

# In Python
from django.urls import reverse
url = reverse('books:detail', kwargs={'pk': 1})

# In templates
{% url 'books:detail' pk=book.pk %}

5. Templates

Template Syntax

{# Comments #}
{{ variable }}
{{ variable|filter }}
{% tag %}

{# Variables #}
{{ book.title }}
{{ book.get_absolute_url }}

{# Filters #}
{{ book.title|lower }}
{{ book.price|floatformat:2 }}
{{ book.description|truncatewords:20 }}
{{ book.published_date|date:"Y-m-d" }}
{{ value|default:"N/A" }}

{# Tags #}
{% if book.is_available %}
    Available
{% elif book.coming_soon %}
    Coming Soon
{% else %}
    Not Available
{% endif %}

{% for book in books %}
    {{ forloop.counter }}: {{ book.title }}
{% empty %}
    No books found
{% endfor %}

{# Template inheritance #}
<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>

<!-- child.html -->
{% extends "base.html" %}
{% block title %}Books{% endblock %}
{% block content %}
    <h1>Book List</h1>
{% endblock %}

{# Include #}
{% include "partials/header.html" %}
{% include "partials/book_item.html" with book=book %}

{# Static files #}
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<img src="{{ book.image.url }}" alt="{{ book.title }}">

{# CSRF token #}
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
</form>

Custom Template Tags & Filters

# templatetags/custom_tags.py
from django import template
register = template.Library()

@register.filter
def multiply(value, arg):
    return value * arg

@register.simple_tag
def current_time(format_string):
    return datetime.now().strftime(format_string)

@register.inclusion_tag('tags/book_list.html')
def show_books(count=5):
    books = Book.objects.all()[:count]
    return {'books': books}

# Usage in template
{% load custom_tags %}
{{ price|multiply:2 }}
{% current_time "%Y-%m-%d" %}
{% show_books 10 %}

6. Forms

Form Definition

from django import forms
from django.core.validators import MinValueValidator

class BookForm(forms.Form):
    title = forms.CharField(max_length=200, required=True)
    author = forms.ChoiceField(choices=Author.objects.values_list('id', 'name'))
    price = forms.DecimalField(validators=[MinValueValidator(0)])
    published_date = forms.DateField(widget=forms.SelectDateWidget)
    
    def clean_title(self):
        title = self.cleaned_data['title']
        if len(title) < 3:
            raise forms.ValidationError("Title too short")
        return title
    
    def clean(self):
        cleaned_data = super().clean()
        # Cross-field validation
        return cleaned_data

class BookModelForm(forms.ModelForm):
    class Meta:
        model = Book
        fields = ['title', 'author', 'price']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'price': forms.NumberInput(attrs={'step': '0.01'})
        }

Form Handling in Views

def create_book(request):
    if request.method == 'POST':
        form = BookForm(request.POST)
        if form.is_valid():
            # Process form.cleaned_data
            return redirect('success')
    else:
        form = BookForm()
    return render(request, 'create_book.html', {'form': form})

Form Rendering

{# Manual rendering #}
{{ form.title.label_tag }}
{{ form.title }}
{{ form.title.errors }}

{# Quick rendering #}
{{ form.as_p }}
{{ form.as_table }}
{{ form.as_ul }}

{# Crispy forms (third-party) #}
{% load crispy_forms_tags %}
{{ form|crispy }}

7. Authentication & Authorization

Built-in Auth Views

from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required, permission_required

def login_view(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user:
            login(request, user)
            return redirect('home')
    return render(request, 'login.html')

@login_required
def profile(request):
    return render(request, 'profile.html')

@permission_required('books.add_book')
def add_book(request):
    # View logic

Custom User Model

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    phone = models.CharField(max_length=15, blank=True)
    date_of_birth = models.DateField(null=True, blank=True)

# In settings.py
AUTH_USER_MODEL = 'accounts.CustomUser'

Permissions

# Model permissions
class Book(models.Model):
    class Meta:
        permissions = [
            ("can_publish", "Can publish books"),
        ]

# Check permissions
if request.user.has_perm('books.can_publish'):
    # Allow action

# In templates
{% if perms.books.can_publish %}
    <button>Publish</button>
{% endif %}

8. Middleware

Custom Middleware

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Code before view
        response = self.get_response(request)
        # Code after view
        return response
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        # Called before view
        return None
    
    def process_exception(self, request, exception):
        # Handle exceptions
        return None

# Register in settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'myapp.middleware.SimpleMiddleware',
    # ...
]

9. Django REST Framework Basics

Serializers

from rest_framework import serializers

class BookSerializer(serializers.ModelSerializer):
    author_name = serializers.CharField(source='author.name', read_only=True)
    
    class Meta:
        model = Book
        fields = ['id', 'title', 'author', 'author_name', 'price']
        read_only_fields = ['id']
    
    def validate_price(self, value):
        if value < 0:
            raise serializers.ValidationError("Price cannot be negative")
        return value

API Views

from rest_framework import viewsets, permissions
from rest_framework.decorators import action
from rest_framework.response import Response

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        queryset = super().get_queryset()
        author = self.request.query_params.get('author')
        if author:
            queryset = queryset.filter(author__id=author)
        return queryset
    
    @action(detail=True, methods=['post'])
    def set_price(self, request, pk=None):
        book = self.get_object()
        book.price = request.data.get('price')
        book.save()
        return Response({'status': 'price set'})

# In urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'books', BookViewSet)
urlpatterns = router.urls

10. Security Best Practices

Settings Configuration

# Security settings
DEBUG = False  # Never True in production
ALLOWED_HOSTS = ['yourdomain.com']
SECRET_KEY = os.environ.get('SECRET_KEY')  # Keep secret

# HTTPS
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000

# Additional security
X_FRAME_OPTIONS = 'DENY'
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True

Common Security Measures

# SQL Injection - Django ORM protects by default
# Never do this:
Book.objects.raw(f"SELECT * FROM books WHERE id = {user_input}")
# Do this:
Book.objects.raw("SELECT * FROM books WHERE id = %s", [user_input])

# XSS Protection - Django auto-escapes templates
{{ user_input }}  # Safe
{{ user_input|safe }}  # Only if you trust the content

# CSRF Protection - Included by default
{% csrf_token %}  # In forms

# Secure file uploads
def validate_file_extension(value):
    valid_extensions = ['.pdf', '.doc', '.docx']
    if not any([value.name.endswith(ext) for ext in valid_extensions]):
        raise ValidationError('Invalid file type')

11. Performance Optimization

Database Optimization

# Use select_related for ForeignKey
books = Book.objects.select_related('author').all()

# Use prefetch_related for ManyToMany
books = Book.objects.prefetch_related('tags').all()

# Use only() to load specific fields
books = Book.objects.only('title', 'price')

# Use defer() to exclude fields
books = Book.objects.defer('content')

# Bulk operations
Book.objects.bulk_create([Book(...), Book(...)])
Book.objects.filter(author=author).update(is_available=False)

# Use indexes
class Book(models.Model):
    title = models.CharField(max_length=200, db_index=True)
    
    class Meta:
        indexes = [
            models.Index(fields=['author', 'published_date']),
        ]

Caching

from django.core.cache import cache
from django.views.decorators.cache import cache_page

# View caching
@cache_page(60 * 15)  # 15 minutes
def book_list(request):
    # ...

# Low-level caching
def get_books():
    books = cache.get('all_books')
    if not books:
        books = Book.objects.all()
        cache.set('all_books', books, 3600)  # 1 hour
    return books

# Template fragment caching
{% load cache %}
{% cache 500 book_list %}
    {% for book in books %}
        {{ book.title }}
    {% endfor %}
{% endcache %}

12. Testing

Unit Tests

from django.test import TestCase, Client
from django.urls import reverse

class BookModelTest(TestCase):
    def setUp(self):
        self.author = Author.objects.create(name="Test Author")
        self.book = Book.objects.create(
            title="Test Book",
            author=self.author,
            price=29.99
        )
    
    def test_string_representation(self):
        self.assertEqual(str(self.book), "Test Book")
    
    def test_get_absolute_url(self):
        self.assertEqual(self.book.get_absolute_url(), f'/books/{self.book.pk}/')

class BookViewTest(TestCase):
    def setUp(self):
        self.client = Client()
        self.book = Book.objects.create(title="Test", price=20)
    
    def test_book_list_view(self):
        response = self.client.get(reverse('books:list'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Test")
    
    def test_book_create_post(self):
        response = self.client.post(reverse('books:create'), {
            'title': 'New Book',
            'price': 25.00
        })
        self.assertEqual(response.status_code, 302)
        self.assertTrue(Book.objects.filter(title='New Book').exists())

Running Tests

# Run all tests
python manage.py test

# Run specific app tests
python manage.py test myapp

# Run with coverage
coverage run --source='.' manage.py test
coverage report

13. Deployment Considerations

Production Settings

# settings/production.py
from .base import *

DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com']

# Database
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME'),
        'USER': os.environ.get('DB_USER'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST'),
        'PORT': '5432',
    }
}

# Static files
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# Media files
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_BUCKET_NAME')

WSGI/ASGI Configuration

# For traditional deployment (Gunicorn + Nginx)
gunicorn myproject.wsgi:application

# For async support (Uvicorn/Daphne)
uvicorn myproject.asgi:application

14. Key Concepts & Comparisons

Field Options Comparison

Option Purpose Example
null=True Allows NULL in database Optional database field
blank=True Allows empty in forms Optional form field
null=True, blank=True Optional in both Completely optional field
default='value' Sets default value Non-null with fallback

Query Optimization Strategies

Problem Solution Usage
N+1 queries select_related() ForeignKey relationships
N+1 queries prefetch_related() ManyToMany relationships
Large objects only('field1', 'field2') Load specific fields only
Unused fields defer('large_field') Exclude heavy fields
Existence check exists() vs count() Faster boolean checks

View Response Methods

Method Purpose Use Case
render() Template + context HTML pages
redirect() HTTP redirect After form submission
HttpResponse() Raw response Plain text, custom content
JsonResponse() JSON data API endpoints

Django Signals

# Common signals and usage
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver

@receiver(post_save, sender=Book)
def create_book_history(sender, instance, created, **kwargs):
    if created:
        BookHistory.objects.create(book=instance)

# Available signals:
# pre_save, post_save, pre_delete, post_delete
# m2m_changed, pre_migrate, post_migrate

Request/Response Cycle

  1. URL Resolution: URLconf matches request path
  2. Middleware Processing: Request middleware runs
  3. View Execution: View function/class processes request
  4. Template Rendering: Template system generates HTML (if needed)
  5. Response Middleware: Response middleware processes output
  6. Client Response: Final response sent to browser

Security Features

Feature Protection Against Implementation
CSRF Token Cross-site request forgery {% csrf_token %} in forms
Auto-escaping XSS attacks {{ variable }} (automatic)
SQL Injection Database attacks ORM parameterized queries
Clickjacking Frame attacks X_FRAME_OPTIONS = 'DENY'

File Upload Handling

# Model
class Document(models.Model):
    file = models.FileField(upload_to='documents/')
    image = models.ImageField(upload_to='images/')

# View
def upload_file(request):
    if request.method == 'POST' and request.FILES['file']:
        # Handle request.FILES['file']
        pass

# Settings
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

15. Best Practices & Quick Reference

Development Best Practices

✅ Security: Use environment variables, enable CSRF protection, validate input
✅ Database: Optimize queries, use indexes, implement caching
✅ Code Quality: Follow PEP 8, write tests, keep views thin
✅ Architecture: Use class-based views for CRUD, separate concerns
✅ Performance: Use pagination, optimize templates, implement caching

Common Django Commands

# Project setup
django-admin startproject myproject
python manage.py startapp myapp

# Database operations
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser

# Development
python manage.py runserver
python manage.py shell
python manage.py test

# Production
python manage.py collectstatic
python manage.py check --deploy

Essential Settings

# Security (Production)
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com']
SECRET_KEY = os.environ.get('SECRET_KEY')
SECURE_SSL_REDIRECT = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True

# Database optimization
DATABASE_CONN_MAX_AGE = 600  # Connection pooling

# Caching
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
    }
}

# Static files
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Performance Optimization Checklist

  • Use select_related() and prefetch_related() to reduce database queries
  • Implement caching with @cache_page decorator or low-level cache API
  • Use database indexes on frequently queried fields
  • Optimize templates by minimizing logic and using template fragment caching
  • Use pagination for large datasets with Paginator class
  • Enable compression and optimize static files delivery

Quick Reference - Template Tags & Filters

{# Common filters #}
{{ value|lower|title }}        # Chain filters
{{ text|truncatewords:10 }}    # Limit words
{{ price|floatformat:2 }}      # Format numbers
{{ date|date:"Y-m-d" }}        # Format dates
{{ list|length }}              # Get length
{{ value|default:"N/A" }}      # Default value

{# Common tags #}
{% for item in items %}
    {{ forloop.counter }}      # Loop counter (1-indexed)
    {{ forloop.counter0 }}     # Loop counter (0-indexed)
    {{ forloop.first }}        # First iteration
    {{ forloop.last }}         # Last iteration
{% empty %}
    No items found
{% endfor %}

{% if condition %}
    {% elif other_condition %}
    {% else %}
{% endif %}

{% with total=items|length %}
    Total: {{ total }}
{% endwith %}

{% url 'app:view_name' pk=object.pk %}  # URL reversal
{% static 'css/style.css' %}            # Static files
{% csrf_token %}                        # CSRF protection

ORM Lookup Reference

# Field lookups
exact, iexact                  # Exact match (case-sensitive/insensitive)
contains, icontains           # Contains (case-sensitive/insensitive)  
startswith, endswith          # String start/end
gt, gte, lt, lte             # Comparisons
in                           # In list
range                        # Between values
isnull                       # NULL checks
year, month, day             # Date parts
week_day                     # Day of week

# Examples
Book.objects.filter(title__icontains='django')
Book.objects.filter(price__range=(10, 50))
Book.objects.filter(published_date__year=2023)
Book.objects.filter(author__name__startswith='J')
Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime