Django turned 20 years old in 2025 and is more relevant than ever for teams that want a full-featured Python web framework without assembling one from parts. In 2026, Django 5.1 adds async ORM support (most methods), a streamlined admin interface, and built-in LoginRequired middleware that replaces decorator boilerplate. If your team is writing Python and building a data-driven web application, Django remains the pragmatic choice over assembling FastAPI + SQLAlchemy + Alembic + Auth from scratch.
What changed in 2026
- Async ORM in Django 5.1.
await Post.objects.filter(published=True).aiterator() and await queryset.aget() are stable. You can write fully async Django views without sync_to_async wrappers for ORM calls.
- Facets in the admin. The admin now shows filter counts inline, reducing the "filter then see zero results" problem in internal tools.
LoginRequired middleware. One line in MIDDLEWARE makes every view require authentication by default; add login_required = False only where needed — a security-by-default win.
- Python 3.12+ only. The
match statement, tomllib, and free-threaded CPython (experimental) are all available. Type hints in Django code are first-class.
Project setup
python -m venv .venv && source .venv/bin/activate
pip install "django>=5.1" psycopg[binary] gunicorn
django-admin startproject mysite .
python manage.py startapp blog
Minimal settings.py additions:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "mysite",
"HOST": "localhost",
}
}
INSTALLED_APPS += ["blog"]
The ORM — learn this before anything else
# models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
class Post(models.Model):
title = models.CharField(max_length=300)
body = models.TextField()
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="posts")
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["-created_at"]
Queryset patterns to learn immediately:
# WRONG — N+1: one query per post
posts = Post.objects.filter(published=True)
for post in posts:
print(post.author.name) # new query per iteration
# RIGHT — one query with JOIN
posts = Post.objects.filter(published=True).select_related("author")
# Prefetch for reverse FK / M2M
from django.db.models import Prefetch
authors = Author.objects.prefetch_related(
Prefetch("posts", queryset=Post.objects.filter(published=True))
)
Run django-debug-toolbar in development to see every query a view fires.
Views: function-based vs class-based
# Function-based (clear, explicit)
from django.shortcuts import render, get_object_or_404
def post_detail(request, pk):
post = get_object_or_404(Post.objects.select_related("author"), pk=pk)
return render(request, "blog/post_detail.html", {"post": post})
# Async function-based (Django 5.1)
async def post_list(request):
posts = [p async for p in Post.objects.filter(published=True).select_related("author")]
return render(request, "blog/post_list.html", {"posts": posts})
Use function-based views for most cases. Class-based views (ListView, DetailView) save boilerplate for simple CRUD — learn them after the basics.
REST API with Django REST Framework
pip install djangorestframework
# serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ["id", "title", "author", "created_at"]
# views.py
from rest_framework.viewsets import ReadOnlyModelViewSet
class PostViewSet(ReadOnlyModelViewSet):
queryset = Post.objects.filter(published=True).select_related("author")
serializer_class = PostSerializer
DRF ViewSets reduce boilerplate for list/detail/create/update/delete patterns.
Django vs FastAPI comparison
| Factor |
Django |
FastAPI |
| Auth, admin, migrations |
Built-in |
Bring your own |
| Async support |
Partial (5.1) |
Full, first-class |
| Data validation |
Forms / DRF serialisers |
Pydantic (excellent) |
| ORM |
Built-in (mature) |
SQLAlchemy / own |
| Learning curve |
Moderate (batteries) |
Moderate (async) |
| Best for |
Full web apps, admin |
APIs, microservices |
How to pick
Build with Django when you need auth, admin, ORM migrations, and email/sessions out of the box. Reach for FastAPI when your entire surface is a JSON API, you need maximum async throughput, or you are building a microservice that does not need a web front end.
Common mistakes
Not using select_related and prefetch_related. The ORM does exactly what you ask. If you ask for 100 posts and access post.author in a loop, you get 101 queries. Use the Django Debug Toolbar to catch this.
Storing secrets in settings.py. Use django-environ or python-decouple to read from environment variables. Never commit SECRET_KEY or database credentials.
Running python manage.py runserver in production. runserver is development-only. Production uses Gunicorn + Nginx (or uvicorn for async).
Missing database indexes. Add db_index=True or explicit class Meta: indexes = [...] on fields used in filter(), order_by(), and get().
What to skip
- South migrations. Django has had built-in migrations since 1.7. Do not install South.
- Custom user models added after the first migration. Django strongly recommends a custom user model from the start. If you skip it, retrofitting later requires squashing all migrations.
django-allauth before you understand Django's built-in auth. Learn LoginView, PasswordChangeView, and sessions first.
FAQ
Is Django still relevant in 2026?
Very much. Instagram, Disqus, and many fintech companies run Django at scale. It is not trendy but it is proven and productive.
Django vs Flask in 2026?
Flask is for microservices where you choose every component. Django is for applications where you want decisions made. The Django team ships more by default; Flask teams spend more time on integration.
How do I handle background tasks?
Celery + Redis is the battle-tested stack. For simpler use cases, django-huey or django-rq are lighter alternatives.
What about Django Channels for WebSockets?
Django Channels adds WebSocket support via ASGI. It works, but for high-concurrency real-time features, a dedicated service (Node.js, Go) may be a better architectural choice.
Where to go next
After Django basics, explore how to learn FastAPI in 2026 to understand the async alternative, how to set up a database in 2026 for production PostgreSQL patterns, and how to containerize an app in 2026 to deploy your application.