Introduction to Django
Django — a powerful open‑source web framework written in Python. It was created in 2003 and first released in 2005. Django follows the “batteries included” principle, meaning it provides all the components needed to build full‑featured web applications without requiring additional packages.
The framework is based on the “Don’t Repeat Yourself” (DRY) principle and offers developers powerful tools for quickly creating secure and scalable web applications.
Architecture and Key Features of Django
MTV pattern (Model‑Template‑View)
Django uses the MTV architectural pattern, which is an adaptation of the classic MVC:
- Model — data model defining the database structure
- Template — template for presenting data to the user
- View — view containing the application’s business logic
Object‑Relational Mapping (ORM)
Django ORM lets you work with the database through Python classes instead of writing SQL queries. This provides:
- Abstraction from a specific DBMS
- Protection against SQL injection
- Easy schema migrations
- Support for multiple database back‑ends
Built‑in Admin Interface
Django automatically generates an admin interface based on your data models. This allows you to:
- Rapidly create CRUD interfaces
- Manage users and permissions
- Perform bulk data operations
- Customize data display and filtering
Security System
Django includes built‑in protection against common vulnerabilities:
- CSRF protection — prevents cross‑site request forgery attacks
- XSS protection — automatic escaping of data in templates
- SQL injection — parameterized queries via ORM
- Clickjacking protection — guards against clickjacking
- Secure cookies — safe cookie handling
- Password hashing — password hashing
Scalability and Performance
Django supports various optimization techniques:
- Caching at multiple levels
- CDN support
- Database query optimization
- Asynchronous request handling (available since version 3.1)
Installation and Configuration of Django
Installing Django
It is recommended to install Django inside a virtual environment:
# Create a virtual environment
python -m venv django_env
# Activate the environment (Windows)
django_env\Scripts\activate
# Activate the environment (macOS/Linux)
source django_env/bin/activate
# Install Django
pip install django
Creating a New Project
# Create the project
django-admin startproject myproject
# Change to the project directory
cd myproject
# Run the development server
python manage.py runserver
After running the commands, the application will be available at: http://127.0.0.1:8000/
Django Project Structure
After creating the project you will get the following structure:
myproject/
│
├── manage.py # Command‑line interface
├── myproject/
│ ├── __init__.py # Makes the directory a Python package
│ ├── settings.py # Project configuration
│ ├── urls.py # Main URL routes
│ ├── wsgi.py # Entry point for WSGI servers
│ └── asgi.py # Entry point for ASGI servers
Description of Main Files:
- manage.py — command‑line utility for managing the project
- settings.py — contains all project settings
- urls.py — defines application URL routes
- wsgi.py — configuration for deployment on WSGI servers
- asgi.py — configuration for asynchronous servers
Creating and Configuring Apps
Creating a New App
python manage.py startapp blog
Registering the App
In settings.py add the new app to INSTALLED_APPS:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # Your app
]
Django App Structure
blog/
├── __init__.py
├── admin.py # Admin configuration
├── apps.py # App configuration
├── models.py # Data models
├── views.py # Views
├── urls.py # App URL routes
├── tests.py # Tests
├── migrations/ # Database migrations
│ └── __init__.py
├── templates/ # HTML templates
└── static/ # Static files
URL Routing and Dispatching
Configuring URL Routes
In the main project urls.py file:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')),
path('', include('blog.urls')), # For the home page
]
Create a blog/urls.py file:
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.index, name='index'),
path('post/<int:post_id>/', views.post_detail, name='post_detail'),
path('create/', views.create_post, name='create_post'),
]
URL Parameters
Django supports various URL parameter types:
<int:id>— integer<str:name>— string<slug:slug>— slug (letters, numbers, hyphens, underscores)<uuid:id>— UUID<path:path>— any path, including slashes
Working with Models and ORM
Creating Models
Define models in models.py:
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Category(models.Model):
name = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True)
description = models.TextField(blank=True)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Post(models.Model):
STATUS_CHOICES = [
('draft', 'Draft'),
('published', 'Published'),
]
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
content = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail', args=[self.id])
Django Field Types
| Field | Purpose |
|---|---|
CharField(max_length) |
Fixed‑length string |
TextField() |
Long text |
IntegerField() |
Integer number |
FloatField() |
Floating‑point number |
BooleanField() |
Boolean value |
DateField() |
Date |
DateTimeField() |
Date and time |
EmailField() |
Email address |
URLField() |
URL address |
SlugField() |
URL‑friendly string (latin, digits, hyphens) |
ImageField() |
Image |
FileField() |
File |
ForeignKey() |
Many‑to‑one relationship |
ManyToManyField() |
Many‑to‑many relationship |
OneToOneField() |
One‑to‑one relationship |
Database Migrations
# Create migrations
python manage.py makemigrations
# Apply migrations
python manage.py migrate
# Show migration SQL
python manage.py sqlmigrate blog 0001
# Roll back migration
python manage.py migrate blog 0001
Working with QuerySets
# Get all objects
posts = Post.objects.all()
# Filter
published_posts = Post.objects.filter(status='published')
# Exclude
draft_posts = Post.objects.exclude(status='published')
# Get a single object
post = Post.objects.get(id=1)
# Safe get
from django.shortcuts import get_object_or_404
post = get_object_or_404(Post, id=1)
# Create
post = Post.objects.create(title='New Post', content='Content')
# Update
Post.objects.filter(id=1).update(title='Updated Title')
# Delete
Post.objects.filter(id=1).delete()
Django Admin Interface
Registering Models
In admin.py:
from django.contrib import admin
from .models import Post, Category
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'status', 'created')
list_filter = ('status', 'created', 'category')
search_fields = ('title', 'content')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'created'
ordering = ('status', 'created')
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
Creating a Superuser
python manage.py createsuperuser
The admin interface is available at: http://127.0.0.1:8000/admin/
Views and HTTP Request Handling
Function‑Based Views
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse, JsonResponse
from django.contrib.auth.decorators import login_required
from .models import Post, Category
def index(request):
posts = Post.objects.filter(status='published')
context = {'posts': posts}
return render(request, 'blog/index.html', context)
def post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id, status='published')
context = {'post': post}
return render(request, 'blog/post_detail.html', context)
@login_required
def create_post(request):
if request.method == 'POST':
# Process form
pass
return render(request, 'blog/create_post.html')
def json_posts(request):
posts = Post.objects.filter(status='published').values('title', 'content')
return JsonResponse(list(posts), safe=False)
Class‑Based Views
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
class PostListView(ListView):
model = Post
template_name = 'blog/index.html'
context_object_name = 'posts'
paginate_by = 10
def get_queryset(self):
return Post.objects.filter(status='published')
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post_detail.html'
context_object_name = 'post'
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content', 'category']
template_name = 'blog/create_post.html'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
Working with Templates
Creating Templates
Create a templates/blog/ directory and add template files:
base.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}My Blog{% endblock %}</title>
{% load static %}
<link rel="stylesheet" href="{% static 'blog/css/style.css' %}">
</head>
<body>
<header>
<nav>
<a href="{% url 'blog:index' %}">Home</a>
{% if user.is_authenticated %}
<a href="{% url 'blog:create_post' %}">Create Post</a>
<a href="{% url 'admin:logout' %}">Logout</a>
{% else %}
<a href="{% url 'admin:login' %}">Login</a>
{% endif %}
</nav>
</header>
<main>
{% block content %}
{% endblock %}
</main>
<footer>
<p>© 2024 My Blog</p>
</footer>
</body>
</html>
index.html:
{% extends 'blog/base.html' %}
{% block title %}Home - {{ block.super }}{% endblock %}
{% block content %}
<h1>Latest Posts</h1>
{% for post in posts %}
<article>
<h2><a href="{% url 'blog:post_detail' post.id %}">{{ post.title }}</a></h2>
<p>Author: {{ post.author.username }} | {{ post.created|date:"d.m.Y" }}</p>
<p>{{ post.content|truncatewords:20 }}</p>
</article>
{% empty %}
<p>No posts yet.</p>
{% endfor %}
{% if is_paginated %}
<nav>
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">Next</a>
{% endif %}
</nav>
{% endif %}
{% endblock %}
Template Tags and Filters
| Tag/Filter | Description |
|---|---|
{% extends %} |
Template inheritance |
{% block %} |
Define a block |
{% include %} |
Include another template |
{% for %} |
Loop |
{% if %} |
Conditional |
{% url %} |
Generate a URL |
{% csrf_token %} |
CSRF token |
{% load %} |
Load custom tags |
{{ var|filter }} |
Apply filter to variable |
{{ var|date:"Y-m-d" }} |
Format date |
{{ var|truncatewords:10 }} |
Truncate to 10 words |
{{ var|safe }} |
Mark as safe HTML |
Django Forms
Creating Forms
from django import forms
from .models import Post, Category
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content', 'category', 'status']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
'category': forms.Select(attrs={'class': 'form-control'}),
'status': forms.Select(attrs={'class': 'form-control'}),
}
def clean_title(self):
title = self.cleaned_data['title']
if len(title) < 5:
raise forms.ValidationError('Title must contain at least 5 characters')
return title
class CommentForm(forms.Form):
name = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control'}))
content = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}))
Processing Forms in Views
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('blog:post_detail', post_id=post.id)
else:
form = PostForm()
return render(request, 'blog/create_post.html', {'form': form})
Working with Static Files and Media
Configuring Static Files
In settings.py:
import os
# Static files
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Serving Static Files via URLconf
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# your URL patterns
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Collecting Static Files
python manage.py collectstatic
Authentication and Authorization System
Built‑in Authentication System
Django provides a ready‑made authentication system with features:
- User registration and login
- Session management
- Permission handling
- User groups and permissions
Access‑Restriction Decorators
from django.contrib.auth.decorators import login_required, permission_required
@login_required
def protected_view(request):
return render(request, 'protected.html')
@permission_required('blog.add_post')
def create_post(request):
return render(request, 'create_post.html')
Custom Authentication Forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class CustomUserCreationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
Creating REST APIs with Django REST Framework
Installing and Configuring DRF
pip install djangorestframework
In settings.py:
INSTALLED_APPS = [
# ...
'rest_framework',
# ...
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}
Creating Serializers
from rest_framework import serializers
from .models import Post, Category
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name', 'slug', 'description']
class PostSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField(read_only=True)
category = CategorySerializer(read_only=True)
class Meta:
model = Post
fields = ['id', 'title', 'slug', 'author', 'content', 'category', 'status', 'created', 'updated']
read_only_fields = ['author', 'created', 'updated']
API Views
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.filter(status='published')
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
@action(detail=True, methods=['post'])
def like(self, request, pk=None):
post = self.get_object()
# Like logic here
return Response({'status': 'liked'})
Middleware and Request Processing
Creating Custom Middleware
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Code executed before the view
response = self.get_response(request)
# Code executed after the view
return response
def process_exception(self, request, exception):
# Exception handling
pass
Registering Middleware
In settings.py:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'myapp.middleware.SimpleMiddleware', # Your middleware
]
Testing Django Applications
Creating Tests
from django.test import TestCase, Client
from django.contrib.auth.models import User
from django.urls import reverse
from .models import Post, Category
class PostModelTest(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
password='testpass123'
)
self.category = Category.objects.create(
name='Test Category',
slug='test-category'
)
def test_post_creation(self):
post = Post.objects.create(
title='Test Post',
content='Test content',
author=self.user,
category=self.category
)
self.assertEqual(post.title, 'Test Post')
self.assertEqual(str(post), 'Test Post')
def test_post_absolute_url(self):
post = Post.objects.create(
title='Test Post',
content='Test content',
author=self.user,
category=self.category
)
self.assertEqual(post.get_absolute_url(), f'/blog/post/{post.id}/')
class PostViewTest(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user(
username='testuser',
password='testpass123'
)
self.category = Category.objects.create(
name='Test Category',
slug='test-category'
)
def test_post_list_view(self):
response = self.client.get(reverse('blog:index'))
self.assertEqual(response.status_code, 200)
def test_post_detail_view(self):
post = Post.objects.create(
title='Test Post',
content='Test content',
author=self.user,
category=self.category,
status='published'
)
response = self.client.get(reverse('blog:post_detail', args=[post.id]))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Test Post')
Running Tests
# Run all tests
python manage.py test
# Run tests for a specific app
python manage.py test blog
# Run with verbose output
python manage.py test --verbosity=2
# Run while keeping the test database
python manage.py test --keepdb
Caching in Django
Configuring Caching
In settings.py:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
}
}
Using the Cache
from django.core.cache import cache
from django.views.decorators.cache import cache_page
# View-level caching
@cache_page(60 * 15) # Cache for 15 minutes
def slow_view(request):
# Slow operation
return render(request, 'slow_template.html')
# Low‑level caching
def get_posts():
posts = cache.get('blog_posts')
if posts is None:
posts = Post.objects.filter(status='published')
cache.set('blog_posts', posts, 60 * 30) # 30 minutes
return posts
Key manage.py Commands
| Command | Description |
|---|---|
runserver |
Start the development server |
startapp <name> |
Create a new app |
makemigrations |
Create migrations |
migrate |
Apply migrations |
createsuperuser |
Create a superuser |
collectstatic |
Collect static files |
shell |
Interactive Django shell |
test |
Run tests |
dbshell |
Database console |
flush |
Clear the database |
dumpdata |
Export data |
loaddata |
Import data |
Django ORM Methods and Functions
| Method | Description |
|---|---|
objects.all() |
Retrieve all objects |
objects.filter() |
Filter objects |
objects.exclude() |
Exclude objects |
objects.get() |
Retrieve a single object |
objects.create() |
Create an object |
objects.update() |
Update objects |
objects.delete() |
Delete objects |
objects.count() |
Count objects |
objects.exists() |
Check existence |
objects.first() |
First object |
objects.last() |
Last object |
objects.distinct() |
Distinct values |
objects.order_by() |
Order results |
objects.select_related() |
Optimize JOINs |
objects.prefetch_related() |
Optimize related queries |
Deploying a Django Project
Preparing for Deployment
- Create requirements.txt:
pip freeze > requirements.txt
- Configure production settings:
# settings/production.py
from .base import *
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com']
# Database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'your_db_name',
'USER': 'your_db_user',
'PASSWORD': 'your_db_password',
'HOST': 'localhost',
'PORT': '5432',
}
}
# Security
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Deployment Options
- Traditional server (Gunicorn + Nginx)
- Containerization (Docker)
- Cloud platforms (Heroku, Railway, Render)
- Cloud providers (AWS, GCP, Azure)
Example Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "myproject.wsgi:application"]
Practical Use Cases for Django
Enterprise Systems
- CRM and ERP systems
- Internal company portals
- Document management systems
- HR systems
Content Platforms
- News sites
- Blogs and magazines
- Forums and social networks
- Educational platforms
E‑commerce
- Online stores
- Marketplaces
- Online booking systems
- Fintech solutions
APIs and Microservices
- RESTful APIs
- GraphQL endpoints
- Microservice architecture
- Integrations with external systems
Frequently Asked Questions
What is Django and what is it used for?
Django is a high‑level Python web framework that encourages rapid development and clean, pragmatic design. It is used to build web applications of any complexity, from simple sites to large‑scale enterprise systems.
How does Django differ from Flask?
Django is a full‑featured “batteries‑included” framework that provides an ORM, admin panel, authentication system, and more out of the box. Flask is a micro‑framework that offers only the basics, with additional functionality added via extensions.
Which databases does Django support?
Django supports PostgreSQL, MySQL, SQLite, Oracle, and other databases through appropriate drivers. PostgreSQL is recommended for production environments.
Is Django suitable for building REST APIs?
Yes, Django works very well for creating REST APIs, especially when combined with Django REST Framework, which offers powerful tools for API development.
Does Django support asynchronous programming?
Since version 3.1, Django supports asynchronous views and middleware via ASGI. Full async support continues to evolve.
How can I ensure the security of a Django application?
Django includes built‑in protection against major vulnerabilities (XSS, CSRF, SQL injection). Additionally, you should use HTTPS, keep dependencies up to date, configure the production environment properly, and follow security best practices.
Can Django handle large projects?
Yes, Django is successfully used in large‑scale projects. Instagram, Pinterest, Mozilla, NASA, and many other major organizations rely on Django for their web applications.
The Future of AI in Mathematics and Everyday Life: How Intelligent Agents Are Already Changing the Game
Experts warned about the risks of fake charity with AI
In Russia, universal AI-agent for robots and industrial processes was developed