Django-powerful web frame

онлайн тренажер по питону
Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

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>&copy; 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

  1. Create requirements.txt:
pip freeze > requirements.txt
  1. 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

  1. Traditional server (Gunicorn + Nginx)
  2. Containerization (Docker)
  3. Cloud platforms (Heroku, Railway, Render)
  4. 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.

News