Backend — Django
Django Framework
The batteries-included Python web framework — MVT architecture, powerful ORM, built-in admin, auth, forms, and deployment. The fastest way to ship production web apps.
Full-StackPython 3.10+Batteries Included
MVTArchitecture
ORMBuilt-in
AdminAuto-generated
AuthBuilt-in
✓Production Ready
The "Batteries-Included" Framework
Django is a high-level Python web framework that encourages rapid development
and clean, pragmatic design. Built by experienced developers, it handles much
of the complexity of web development so you can focus on writing your app.
01
Everything Built-In
ORM, authentication, admin panel, forms, templates, sessions, caching — no hunting for third-party libraries for core functionality.
python
# Django provides all of this out of the box
from django.contrib.auth.models import User
from django.db import models
from django.contrib.admin import site
from django.forms import ModelForm
from django.core.cache import cache
from django.core.mail import send_mail
02
DRY Philosophy — Define Once, Use Everywhere
Write your data model once. Django auto-generates the database schema, admin interface, forms, and API serializers from it.
python
# Define model ONCE in models.py
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField(default=0)
# Django auto-generates:
# Database table (via migration)
# Admin CRUD interface
# ModelForm for HTML forms
# REST serializer (with DRF)
03
Secure by Default
Protection against the most common web vulnerabilities is baked in — you have to explicitly opt out to turn it off.
python
# settings.py — security features enabled by default
CSRF_COOKIE_SECURE = True # CSRF token required on all POST forms
SESSION_COOKIE_SECURE = True # Sessions over HTTPS only
X_FRAME_OPTIONS = 'DENY' # Clickjacking protection
SECURE_HSTS_SECONDS = 31536000 # HTTP Strict Transport Security
# SQL injection: Django ORM escapes all queries automatically
# XSS: Django templates auto-escape HTML by default
04
Scalable — From Blog to Instagram
Instagram serves over 1 billion users on Django. Its architecture supports horizontal scaling, database sharding, and caching layers.
Instagram was built on Django from day one and still runs it today — proving Django scales far beyond "just for small projects."
2005
Year Released
Built at Lawrence Journal-World newspaper
5.x
Current Version
Full async support, improved ORM
BSD
License
Open source, maintained by DSF
1B+
Instagram Users
Most famous Django-powered app
MVT — Model · View · Template
Django follows the MVT pattern. It looks like MVC, but Django calls the
"Controller" layer the View, and the presentation layer the Template.
The framework itself acts as the controller routing requests.
M
Model
Data & Database
⇄
V
View
Business Logic
⇄
T
Template
HTML Presentation
M
Model — The Data Layer
Python classes that map directly to database tables. Django ORM handles all SQL generation automatically.
models.py
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
published = models.BooleanField(default=False)
class Meta:
ordering = ['-created']
def __str__(self):
return self.title
V
View — The Business Logic Layer
Functions or classes that receive an HTTP request, interact with the Model, and return a response.
views.py
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from .models import Post
def post_list(request):
posts = Post.objects.filter(published=True)
return render(request, 'blog/list.html', {'posts': posts})
@login_required
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/detail.html', {'post': post})
T
Template — The Presentation Layer
HTML files with Django Template Language (DTL) — variables, loops, conditionals, and template inheritance.
html (dtl)
{# blog/list.html #}
{% extends 'base.html' %}
{% block content %}
<h1>Latest Posts</h1>
{% for post in posts %}
<article>
<h2>{{ post.title }}</h2>
<p>by {{ post.author }} · {{ post.created|date:"M d, Y" }}</p>
</article>
{% empty %}
<p>No posts yet.</p>
{% endfor %}
{% endblock %}
The URL dispatcher acts as Django's controller — it routes incoming requests to the right View function based on the URL pattern.
Django ORM — Object-Relational Mapper
The ORM lets you interact with your database using Python instead of SQL.
Queries are lazy (only execute when needed) and chainable.
Supports PostgreSQL, MySQL, SQLite, and Oracle.
01
CRUD Operations
Create, Read, Update, Delete — the four core database operations.
python
# CREATE
post = Post.objects.create(title="Hello", content="World", author=user)
# READ — single object
post = Post.objects.get(pk=1) # raises DoesNotExist if missing
post = Post.objects.filter(pk=1).first() # returns None if missing
# READ — queryset (lazy, evaluated on iteration)
posts = Post.objects.filter(published=True).order_by('-created')[:10]
# UPDATE
Post.objects.filter(author=user).update(published=True)
# DELETE
Post.objects.filter(published=False).delete()
02
QuerySet Chaining & Lookups
Filter with double-underscore (dunder) field lookups. Queries are lazy — no DB hit until you evaluate.
python
# Field lookups with __ (dunder) syntax
Post.objects.filter(title__icontains='django') # case-insensitive search
Post.objects.filter(created__year=2024) # filter by year
Post.objects.filter(author__username='omer') # traverse FK relationship
Post.objects.exclude(published=False) # exclude filter
# Chaining (lazy — single SQL query generated)
results = (
Post.objects
.filter(published=True)
.select_related('author') # JOIN to avoid N+1
.prefetch_related('tags') # prefetch M2M
.order_by('-created')
.values('title', 'author__username')
)
03
Model Relationships
ForeignKey (many-to-one), ManyToManyField, OneToOneField — Django handles the JOIN logic for you.
python
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
class Post(models.Model):
# ForeignKey: many Posts → one Author
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
# ManyToMany: a Post can have many Tags, a Tag many Posts
tags = models.ManyToManyField(Tag, blank=True)
# Reverse access via related_name
user.posts.filter(published=True).count() # all posts by user
04
Migrations — Schema Version Control
Every model change generates a migration file. Your database schema is always in sync with your code.
bash
# After changing a model, always run:
python manage.py makemigrations # generates migration file
python manage.py migrate # applies changes to DB
# Inspect the generated SQL before applying:
python manage.py sqlmigrate myapp 0001
# Check for unapplied migrations:
python manage.py showmigrations
Always use
select_related() for ForeignKey fields and prefetch_related() for M2M fields when looping through querysets. Forgetting this causes the N+1 query problem.
Django Admin — Free CRUD Interface
Register any model and instantly get a production-quality admin dashboard —
list views, search, filters, form editing, and permissions — with zero extra code.
01
Register Models
One decorator turns any model into a full admin interface.
admin.py
from django.contrib import admin
from .models import Post, Tag
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'published', 'created']
list_filter = ['published', 'created']
search_fields = ['title', 'content', 'author__username']
list_editable = ['published'] # edit inline in list view
prepopulated_fields = {'slug': ('title',)} # auto-generate slug
date_hierarchy = 'created'
admin.site.register(Tag)
02
Inline Models
Edit related objects directly within a parent object's admin page.
admin.py
class CommentInline(admin.TabularInline):
model = Comment
extra = 1 # show 1 empty form by default
fields = ['author', 'body', 'approved']
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
inlines = [CommentInline] # Comments appear inside Post admin
03
Superuser & Permissions
Django's permission system controls who can view, add, change, or delete each model.
bash
# Create admin superuser
python manage.py createsuperuser
# Access at: http://127.0.0.1:8000/admin/
The admin panel is available at
/admin/ by default. For production, consider changing this URL to something less obvious for security.
URLs & Views
Django maps URL patterns to view functions/classes. Each app has its own
urls.py, which is included in the project's root URL configuration.
01
URL Configuration
Use
path() for exact matches and re_path() for regex patterns. URL parameters are captured with angle brackets.urls.py
from django.urls import path, include
from . import views
# app/urls.py
urlpatterns = [
path('', views.post_list, name='post-list'),
path('posts/<int:pk>/', views.post_detail, name='post-detail'),
path('posts/<slug:slug>/', views.post_slug, name='post-slug'),
path('category/<str:name>/', views.by_category, name='category'),
]
# project/urls.py — include app URLs
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')),
path('api/', include('api.urls')),
]
02
Function-Based Views (FBV)
Simple, explicit. Best for custom logic where a CBV would be harder to read.
views.py
from django.shortcuts import render, redirect
from django.http import JsonResponse
from .forms import PostForm
def create_post(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('post-detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'blog/create.html', {'form': form})
03
Class-Based Views (CBV)
Generic views eliminate boilerplate for common patterns — list, detail, create, update, delete.
views.py
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
class PostListView(ListView):
model = Post
template_name = 'blog/list.html'
context_object_name = 'posts'
paginate_by = 10
queryset = Post.objects.filter(published=True)
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content', 'tags']
success_url = reverse_lazy('post-list')
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
Authentication & Permissions
Django ships with a complete authentication system — user model, sessions,
login/logout views, password hashing (PBKDF2), and a group/permission system.
No third-party packages required.
01
Built-In Auth Views
Django provides ready-made views for login, logout, password change, and password reset. Just wire up the URLs.
urls.py
from django.contrib.auth import views as auth_views
urlpatterns = [
# Login / Logout
path('login/', auth_views.LoginView.as_view(), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
# Password reset (full email flow)
path('password/reset/', auth_views.PasswordResetView.as_view()),
path('password/reset/done/', auth_views.PasswordResetDoneView.as_view()),
path('password/reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view()),
]
02
Protecting Views
Use decorators (FBV) or mixins (CBV) to restrict access to authenticated users.
python
from django.contrib.auth.decorators import login_required, permission_required
# Redirect to /login/ if not authenticated
@login_required
def dashboard(request):
return render(request, 'dashboard.html')
# Require specific permission
@permission_required('blog.can_publish', raise_exception=True)
def publish_post(request, pk):
Post.objects.filter(pk=pk).update(published=True)
return redirect('post-detail', pk=pk)
03
Custom User Model
Always extend the default User model at the start of a project. Much harder to change later.
models.py
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
bio = models.TextField(blank=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
# settings.py
AUTH_USER_MODEL = 'accounts.CustomUser'
Set
AUTH_USER_MODEL before your first migration. Changing it after creating database tables is painful and error-prone.
Deploying Django to Production
Django's development server is not suitable for production. Use Gunicorn/Daphne,
configure production settings, serve static files via a CDN or whitenoise, and
deploy to Railway, Render, Heroku, or a VPS.
01
Production Settings Checklist
Never run
DEBUG=True in production. Use environment variables for secrets.settings.py
import os
# Never hardcode SECRET_KEY in production
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
# Database (use PostgreSQL in production)
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'),
}
}
# Static files (WhiteNoise for serving without Nginx)
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
02
Gunicorn WSGI Server
Gunicorn is the standard WSGI server for Django in production. For async views, use Daphne (ASGI) instead.
bash
pip install gunicorn
# Run with 4 worker processes
gunicorn myproject.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 4 \
--timeout 120
# For async (Django Channels / ASGI)
pip install daphne
daphne myproject.asgi:application --bind 0.0.0.0 --port 8000
03
Deploy to Railway (recommended for quick deploys)
Railway auto-detects Django projects. Add a Procfile and environment variables.
bash
# Procfile
web: gunicorn myproject.wsgi --log-file -
# runtime.txt (specify Python version)
python-3.12.0
# Pre-deploy commands (railway.toml or Dashboard)
python manage.py migrate
python manage.py collectstatic --noinput
Django Complete Cheatsheet
Everything from project setup to production — all patterns, commands, and best practices in one place.
① Installation & Project Setup
bash
# Install Django
pip install django psycopg2-binary whitenoise
django-admin --version
# Create project & app
django-admin startproject projectName
cd projectName
python manage.py startapp AppName
# Register app in settings.py → INSTALLED_APPS += ['AppName']
python manage.py runserver # http://127.0.0.1:8000/
python manage.py runserver 8080 # custom port
② MVT Patterns
models.py
from django.db import models
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
price = models.FloatField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
views.py — FBV & CBV
from django.shortcuts import render, redirect
from django.views import View
from django.http import HttpResponse
# Function-Based View
def index(request):
return render(request, 'index.html', {'title': 'Welcome'})
# Class-Based View
class SimpleView(View):
def get(self, request):
return HttpResponse('Hello from CBV')
# Redirect
def go_home(request):
return redirect('https://example.com')
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('about/', views.about, name='about'),
# Modular apps
path('community/', include('aggregator.urls')),
]
③ Forms
forms.py
from django import forms
class SampleForm(forms.Form):
name = forms.CharField(max_length=50)
description = forms.CharField(widget=forms.Textarea)
④ Templates
settings.py — template config
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
}]
# Pass variable in view:
# return render(request, 'index.html', {"name": "Omer"})
# Access in template: <h1>Hello, {{ name }}</h1>
⑤ Admin
admin.py
from django.contrib import admin
from .models import Product
admin.site.register(Product) # simple
# Or with customization:
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ['name', 'price', 'created_at']
search_fields = ['name']
⑥ Best Practices
Use virtual environments for every project.
Always commit
Use .env files for secrets — never hardcode them in settings.
Separate dev & production settings (use
Prefer class-based views for reusable, scalable code.
Always commit
requirements.txt: pip freeze > requirements.txtUse .env files for secrets — never hardcode them in settings.
Separate dev & production settings (use
django-environ).Prefer class-based views for reusable, scalable code.
⑦ All manage.py Commands
| Command | What it does |
|---|---|
python manage.py runserver | Start dev server at localhost:8000 |
python manage.py runserver 8080 | Start on custom port |
python manage.py startapp <name> | Create a new app inside the project |
python manage.py makemigrations | Generate migration files from model changes |
python manage.py migrate | Apply migrations to the database |
python manage.py sqlmigrate app 0001 | View SQL for a specific migration |
python manage.py createsuperuser | Create an admin superuser |
python manage.py shell | Open interactive Django shell with ORM access |
python manage.py collectstatic | Gather all static files to STATIC_ROOT |
python manage.py showmigrations | List all migrations and their applied status |
python manage.py dbshell | Open the raw database CLI |
python manage.py check | Check project for common issues |
python manage.py test | Run the test suite |
Test Your Django Knowledge
10 interview-style questions covering ORM, middleware, security, deployment, and Django internals.
1In Django's MVT pattern, what is the role of the View?
2Which ORM method avoids the N+1 query problem when accessing a ForeignKey field in a loop?
3What does
python manage.py makemigrations do?4Which decorator protects a view so only logged-in users can access it?
5When should you set
AUTH_USER_MODEL in settings?6Which method fixes N+1 queries on a reverse ForeignKey (many side) in a loop?
7What is Django middleware primarily used for?
8How does Django CSRF protection work for POST forms?
9Typical production Django deployment stack?
10Django signals are best used for…
—
Keep practicing!