New in 2026: Master Python for AI, Data Science

DjangoProgramming

Introduction to Django Web Framework

Introduction to Django Web Framework

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

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. Use condition= with Q objects 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 AsyncClient for 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 articles first, then add the app to INSTALLED_APPS in settings.py before running makemigrations. Forgetting this order is the most common migration error.
  • Using check= in CheckConstraint on Django 5+. The check= parameter is deprecated. Use condition= with a Q object. 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 trigger save() signals or update timestamps. If you need signals or auto_now fields to fire, loop and save each object individually.
  • Confusing auto_now_add with auto_now. auto_now_add=True only sets the field on creation. auto_now=True updates it on every .save(). Use the right one for your use case — they can’t be set manually via create().
  • 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_APPS in settings.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:

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.

Related posts
ProgrammingPython

Production-Ready MCP Servers — Security, Testing & Deployment

ProgrammingPython

Build Your First MCP Server with Python SDK — Fundamentals

ProgrammingPython

Connect FastAPI to MCP — Two Integration Patterns

ProgrammingPython

Replace pip with uv for Faster Python Development

Leave a Reply