You’ve built Flask apps and they work fine. But now you need user authentication, an admin panel, database migrations, and a structure that scales without you constantly reinventing the wheel. That’s where Django comes in — and it’s not as hard to learn as the documentation makes it look. Here’s where to start.
In this tutorial, you will learn to:
- Set up a Django project and app on Django 5.x
- Define models with Django’s ORM and run migrations
- Write views and route URLs with Django’s path() function
- Render HTML with Django’s template engine
- Use the auto-generated admin panel for CRUD operations
- Apply Django 5.0 features like db_default and field groups
- Understand when Django is the right choice over Flask
Page Contents
What Is Django?
Django is a high-level Python web framework that follows the “batteries included” philosophy. It ships with an ORM, admin panel, authentication, form handling, and more — all pre-built and production-ready. Django 5.x (released December 2023 through 2025) is the current version, with Django 5.2 being the latest LTS as of April 2025.
If you’re unfamiliar with Python itself, start with the Introduction to Python Programming before continuing.
Django Architecture — Request Flow
Every Django request follows the same path:
REQUEST
|
v
urls.py --> URL routing
|
v
views.py --> Request handling
|
v
models.py --> Database operations
|
v
templates --> HTML response
|
v
RESPONSE
- urls.py — Maps URLs to view functions
- views.py — Contains request handling logic
- models.py — Defines database schema as Python classes
- templates/ — HTML files with Django’s template syntax
Prerequisites
You’ll need Python installed (3.10+ for Django 5.x), and basic familiarity with classes, functions, and virtual environments. If you’re new to Python, see the Python programming intro and strings guide first.
Installing Django
Django 5.x requires Python 3.10 or later. Install it in a virtual environment:
python -m venv venv
source venv/bin/activate # Windows: venvScriptsactivate
pip install django
django-admin --version # Should show 5.2.x
Creating a Project
django-admin startproject mysite
cd mysite
python manage.py startapp articles
This creates the project structure. The articles app is where your blog functionality lives. Your project layout looks like this:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
articles/
__init__.py
models.py
views.py
admin.py
Defining Models
Django’s ORM lets you define database tables as Python classes. Each class maps to a table; each attribute maps to a column. Django 5.0 introduced db_default for database-computed defaults and improved CheckConstraint syntax.
# articles/models.py
from django.db import models
from django.db.models import CheckConstraint, Q
class Article(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
content = models.TextField()
author = models.CharField(max_length=100)
published_date = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
is_draft = models.BooleanField(default=True)
view_count = models.PositiveIntegerField(default=0, db_default=0)
# Django 5.0: db_default sets a database-level default
status = models.CharField(
max_length=20,
default='draft',
db_default='draft'
)
class Meta:
ordering = ['-published_date']
constraints = [
# Django 5.0+: use condition= instead of check=
CheckConstraint(
condition=Q(status__in=['draft', 'published', 'archived']),
name='valid_article_status'
),
]
def __str__(self):
return self.title
What’s new in Django 5.0+: The db_default parameter sets a database-level default — it fires at the database level rather than in Python, which is more efficient for high-write workloads. The new constraint syntax condition= replaces the deprecated check= parameter in CheckConstraint.
Running Migrations
After defining models, create and apply migrations to sync your database schema:
python manage.py makemigrations
# Output: Migrations for 'articles' created:
# articles/migrations/0001_initial.py
python manage.py migrate
# Output: Operations to perform:
# Apply all. Creating tables...
# Creating table articles_article... OK
Django ORM — Query Examples
# Create a new article
article = Article.objects.create(
title='Hello World',
slug='hello-world',
content='Django is amazing!',
author='Aditya',
is_draft=False
)
print(f"Created: {article}")
# Read all published articles, newest first
articles = Article.objects.filter(
is_draft=False
).order_by('-published_date')[:3]
for a in articles:
print(f"- {a.title} by {a.author}")
# Find single article
article = Article.objects.get(slug='hello-world')
# Update
Article.objects.filter(slug='hello-world').update(view_count=models.F('view_count') + 1)
# Delete
article.delete()
Your First View and Template
Django views receive an HTTP request and return an HTTP response. The simplest is HttpResponse, but real projects use templates to render HTML.
# articles/views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Article
def article_list(request):
articles = Article.objects.filter(is_draft=False)[:5]
return render(request, 'articles/article_list.html', {
'articles': articles
})
def article_detail(request, slug):
article = Article.objects.get(slug=slug)
return HttpResponse(f"{article.title}
{article.content}
")
Create a template at articles/templates/articles/article_list.html:
{% extends 'base.html' %}
{% block content %}
Latest Articles
{% for article in articles %}
-
{{ article.title }}
by {{ article.author }}
{% empty %}
- No articles yet.
{% endfor %}
{% endblock %}
URL Routing
Connect views to URLs using path() in your project’s urls.py:
# mysite/urls.py
from django.contrib import admin
from django.urls import path
from articles.views import article_list, article_detail
urlpatterns = [
path('admin/', admin.site.urls),
path('articles/', article_list, name='article_list'),
path('articles//', article_detail, name='article_detail'),
]
The <slug:slug> converter captures a URL slug and passes it to the view as a keyword argument. Django provides converters for int, str, slug, uuid, and path.
Django Admin Panel
One of Django’s killer features: an auto-generated admin panel. Register your model and you get a full CRUD interface at /admin/ — no HTML, no JavaScript, just Python.
# articles/admin.py
from django.contrib import admin
from .models import Article
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'published_date', 'is_draft']
list_filter = ['is_draft', 'published_date']
search_fields = ['title', 'content']
prepopulated_fields = {'slug': ('title',)}
date_hierarchy = 'published_date'
Visit http://localhost:8000/admin/, create a superuser with python manage.py createsuperuser, and manage your articles from a web interface. The @admin.register decorator and ModelAdmin class give you a polished, customizable admin — a feature that would take days to build from scratch in Flask.
Django 5.0 — Key New Features
If you’re coming from Django 4.x or starting fresh in 2026, these Django 5.0 features are worth knowing:
- Field.db_default — Sets database-level default values. More efficient than Python-side defaults for high-write tables. See the official docs.
- CheckConstraint(condition=) — The
check=parameter is deprecated. Usecondition=withQobjects instead:CheckConstraint(condition=Q(age__gte=18), name='age_of_consent'). - Field groups — Reusable groups of model fields that can be applied across multiple models, reducing boilerplate.
- Async client improvements — Django 5.0 added more async test methods to
AsyncClientfor testing async views.
Why Django over Flask?
- Built-in ORM — No SQLAlchemy setup needed; migrations are first-class citizens
- Admin panel — Auto-generated CRUD interface at
/admin/ - Database migrations — Version-controlled schema changes with
makemigrations/migrate - Authentication — Built-in user management, session handling, and permissions
- Structure — Django enforces a project layout that scales without you making architectural decisions on every new project
- Forms & ModelForms — Handle validation and HTML rendering automatically
- Django REST Framework — Pairs seamlessly with Django for building REST APIs
Flask is great for small projects, APIs, and microservices where you want full control. Django is the right choice when you need a full-featured web application with database-backed models, an admin interface, and a structure that grows with the project. For a side project like a blog or a startup MVP, Django’s admin panel alone saves weeks of work.
Common Mistakes / Gotchas
- Running migrations before creating the app. Always run
startapp articlesfirst, then add the app toINSTALLED_APPSinsettings.pybefore runningmakemigrations. Forgetting this order is the most common migration error. - Using
check=in CheckConstraint on Django 5+. Thecheck=parameter is deprecated. Usecondition=with aQobject. It raises a deprecation warning on Django 5.0 and will break on Django 6.0. - Not calling
.save()after.update().QuerySet.update()writes directly to the database and returns the number of rows affected — it does NOT triggersave()signals or update timestamps. If you need signals orauto_nowfields to fire, loop and save each object individually. - Confusing
auto_now_addwithauto_now.auto_now_add=Trueonly sets the field on creation.auto_now=Trueupdates it on every.save(). Use the right one for your use case — they can’t be set manually viacreate(). - Forgetting to add your app to INSTALLED_APPS. If Django can’t find your models in the admin, the first thing to check is that the app name appears in
INSTALLED_APPSinsettings.py.
Summary & Next Steps
You now know how to set up a Django project, define models with Django 5.0 features, write views, route URLs, render templates, and use the admin panel. Django’s batteries-included approach means you can build a production-ready blog in an afternoon — not a week.
Next, explore these topics:
- Introduction to Python Programming — if you’re new to Python
- Python Strings: The Complete Guide — essential Python reading
- Official Django Documentation — the authoritative reference
- Python Print Formatting Guide — for debugging your Django apps
Django’s official tutorial at docs.djangoproject.com/en/6.0/intro/ is an excellent next step to go deeper on views, forms, and testing.

