Django rewards engineers who think in systems, not shortcuts. This guide walks through the parts that actually matter when you are starting a real project: environment setup, the project versus app distinction, how models drive your data layer, the view and URL routing system, templates, and why the admin interface is worth understanding early. Whether you are coming from Flask, Express, or Rails, the patterns here will help you build with Django’s grain rather than against it. For a broader view of the framework’s surface area, see our Framework overview.
Starting a Django project is straightforward, but the choices you make in the first hour shape how the project scales over the next year. I have seen teams spend weeks untangling a flat project structure or fighting circular imports because the initial layout was never questioned. The investment in getting the skeleton right pays off fast.
Prerequisites and environment setup
Before writing any Django code, you need Python 3.10 or later and a clean virtual environment. Do not install Django globally. Every project should have its own isolated dependency set. If you are unsure how to set this up properly, our Python environments guide covers virtual environments, pip, and dependency locking in detail.
python -m venv .venv
source .venv/bin/activate # macOS / Linux
.venv\Scripts\activate # Windows
pip install django
Once Django is installed, confirm the version:
python -m django --version
You want 5.1 or later for the best defaults and security posture.
Creating a project versus creating an app
Django separates the project container from individual apps. The project holds settings, root URL configuration, and the WSGI or ASGI entry point. Apps hold models, views, templates, and business logic for a specific domain.
django-admin startproject mysite .
python manage.py startapp catalog
That trailing dot after startproject places manage.py at the root instead of nesting it inside an extra directory. Teams that skip this end up with an unnecessary layer of folders that confuses deployment tooling and IDE configurations.
A fresh Django project gives you:
manage.pyfor running commandssettings.pyfor configurationurls.pyfor the root URL dispatcherwsgi.pyandasgi.pyfor production server entry points
Each app you create adds its own models.py, views.py, urls.py, admin.py, and tests.py. Treat each app as a self-contained module with a clear responsibility.
Models and the database layer
Django’s ORM maps Python classes to database tables. You define fields, relationships, and constraints in a model class, and Django handles the SQL generation through migrations.
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.name
After defining your model, generate and apply migrations:
python manage.py makemigrations
python manage.py migrate
Every model change requires a new migration. Do not edit migration files by hand unless you genuinely understand the migration graph. Our ORM query optimization guide covers the performance side of model design once you have the basics down.
Views, URLs, and the request cycle
Django processes every HTTP request through a URL dispatcher, which matches the incoming path to a view function or class. Views receive the request, interact with models or services, and return a response.
from django.shortcuts import render, get_object_or_404
from .models import Product
def product_detail(request, slug):
product = get_object_or_404(Product, slug=slug)
return render(request, 'catalog/product_detail.html', {'product': product})
Wire the view into a URL pattern:
from django.urls import path
from . import views
urlpatterns = [
path('products/<slug:slug>/', views.product_detail, name='product_detail'),
]
Include this app’s URL configuration in the project root urls.py with include(). Keeping URL definitions inside each app means no single file becomes a routing monolith as the project grows.
Templates and the rendering pipeline
Django templates use a block inheritance model that keeps HTML DRY. You create a base template with shared structure, then extend it in page-specific templates:
<!-- base.html -->
<!DOCTYPE html>
<html lang="en">
<head><title>{% block title %}My Site{% endblock %}</title></head>
<body>
{% block content %}{% endblock %}
</body>
</html>
<!-- catalog/product_detail.html -->
{% extends "base.html" %}
{% block title %}{{ product.name }}{% endblock %}
{% block content %}
<h1>{{ product.name }}</h1>
<p>{{ product.description }}</p>
{% endblock %}
Template logic should stay minimal. Heavy data processing belongs in views or model methods, not in template tags. Keep templates focused on presentation.
The admin interface
Django ships with a production-grade admin interface that gives you CRUD operations for every registered model. It is not a throwaway scaffold. Teams use it daily for content management, data inspection, and internal operations.
from django.contrib import admin
from .models import Product
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ['name', 'price', 'created_at']
search_fields = ['name']
prepopulated_fields = {'slug': ('name',)}
Register your models and create a superuser:
python manage.py createsuperuser
python manage.py runserver
Visit /admin/ and log in. You will have a working interface for managing your data immediately. Our admin customization guide covers list filters, inline editing, custom actions, and theming once you need more from the admin.
Static files and running the dev server
Static files like CSS, JavaScript, and images live in each app’s static/ directory or a project-level staticfiles/ directory. During development, Django serves them automatically. In production, you need to collect and serve them through a proper CDN or web server. The static files and media guide covers this transition in detail.
For documentation on Django’s full feature set, the official Django documentation is the authoritative reference and worth bookmarking early.
What to learn next
Once the basics are solid, the next steps depend on what you are building:
- Data-heavy applications: start with the ORM optimization guide
- Production deployments: read the production settings guide
- Authentication flows: see the authentication patterns guide
- Background processing: explore the Celery integration guide
- Testing confidence: review the testing strategy guide
Frequently asked questions
Should I use function-based views or class-based views? Start with function-based views. They are explicit, easy to follow, and force you to understand the request cycle. Move to class-based views when you genuinely need the mixins and inheritance for reducing repetition across similar views.
How many apps should a project have? There is no magic number. Each app should represent a distinct domain concept. A small project might have two or three apps. A large platform might have twenty. The key is that each app can be described in one sentence.
Do I need Docker to develop with Django? No. A virtual environment and SQLite are sufficient for most development. Docker becomes valuable when you need PostgreSQL, Redis, or Celery running locally, or when you want to match your production environment closely.
When should I switch from SQLite to PostgreSQL? Before your first real deployment. SQLite works fine for local development, but PostgreSQL gives you proper concurrency, full-text search, JSON fields, and the reliability guarantees you need in production. See our PostgreSQL production guide.
Is Django still a good choice in 2026? Django handles more production traffic than most developers realize. Its stability, built-in admin, mature ORM, and security defaults make it an excellent choice for teams that prioritize shipping reliable software over chasing framework trends.