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 requirements.txt: pip freeze > requirements.txt
Use .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
CommandWhat it does
python manage.py runserverStart dev server at localhost:8000
python manage.py runserver 8080Start on custom port
python manage.py startapp <name>Create a new app inside the project
python manage.py makemigrationsGenerate migration files from model changes
python manage.py migrateApply migrations to the database
python manage.py sqlmigrate app 0001View SQL for a specific migration
python manage.py createsuperuserCreate an admin superuser
python manage.py shellOpen interactive Django shell with ORM access
python manage.py collectstaticGather all static files to STATIC_ROOT
python manage.py showmigrationsList all migrations and their applied status
python manage.py dbshellOpen the raw database CLI
python manage.py checkCheck project for common issues
python manage.py testRun 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!