Django остаётся одним из самых практичных способов сделать веб-приложение на Python: в нём уже есть ORM, миграции, административная панель, шаблоны, формы и защита от типовых атак. На нём удобно писать и небольшой сайт, и внутренний сервис с авторизацией и базой данных. Разберём путь от пустого каталога до рабочего приложения за обратным прокси.
Что даёт Django
Фреймворк придерживается принципа «батарейки в комплекте». Разработчик описывает модели данных на Python, получает автоматические миграции и может сразу открыть админку для управления записями. Шаблонизатор экранирует переменные по умолчанию, ORM подставляет параметры в SQL, а CSRF-защита включена в стандартный набор middleware.
Django не диктует структуру бизнес-логики, но задаёт понятные границы: проект содержит настройки и корневые маршруты, приложения — модели, представления, шаблоны и тесты. Для долгоживущего проекта разумно выбрать LTS-ветку 5.2: она поддерживается до 2028 года. Ветка 6.0 требует более свежего Python и подходит, если зависимости уже обновлены.
Окружение и установка
Не ставьте пакеты в системный Python. Виртуальное окружение изолирует зависимости и позволяет обновлять проект независимо от других сервисов на машине. Для PostgreSQL нужен драйвер psycopg, для запуска приложения — Gunicorn.
sudo apt install python3-venv python3-pip postgresql
python3 -m venv .venv
source .venv/bin/activate
pip install "Django>=5.2,<6.0" "psycopg[binary]" gunicorn
django-admin startproject config .
python manage.py startapp blog
Точка в конце команды startproject важна: она создаёт файлы управления в текущем каталоге, а не во вложенной папке. В результате рядом лежат manage.py и каталог config с настройками.
Модели и миграции
Модель — это описание таблицы и одновременно слой бизнес-правил. Поля задают тип и ограничения, Meta управляет сортировкой, а метод __str__ делает записи читаемыми в админке. Миграции хранят историю изменений схемы в виде Python-файлов, поэтому их применяют и на рабочей машине, и на сервере.
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
body = models.TextField()
is_published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["-created_at"]
def __str__(self):
return self.title
После изменения модели выполняют makemigrations, затем migrate. Команда createsuperuser нужна один раз, чтобы получить доступ к административной панели. Если миграция получилась ошибочной и ещё не применялась, её файл можно удалить и сгенерировать заново; для уже применённой схемы так делать нельзя.
python manage.py makemigrations blog
python manage.py migrate
python manage.py createsuperuser
Маршруты и представления
Представление принимает запрос и возвращает ответ. Самое простое — функция, которая выбирает данные через ORM и передаёт их в шаблон. Маршруты удобно держать внутри приложения, а в корневом urls.py подключать их через include.
from django.shortcuts import render
from .models import Post
def post_list(request):
posts = Post.objects.filter(is_published=True)
return render(request, "blog/post_list.html", {"posts": posts})
В шаблоне цикл по posts выводит заголовок и короткий фрагмент текста. Не забывайте про наследование шаблонов: базовый файл хранит меню и подвал, а дочерние переопределяют только блок контента. Статические файлы — CSS и JavaScript — подключают через тег static, а не прописывают абсолютным путём.
Настройки для production
Файл settings.py в репозитории содержит только безопасные значения по умолчанию. Секретный ключ, пароль базы и адреса хостов передают через переменные окружения. Флаг DEBUG обязательно выключают: при нём Django показывает трассировки и настройки, что недопустимо на публичном сайте.
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
DEBUG = False
ALLOWED_HOSTS = ["example.ru", "www.example.ru"]
CSRF_TRUSTED_ORIGINS = ["https://example.ru"]
STATIC_ROOT = BASE_DIR / "staticfiles"
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
Базу описывают через словарь DATABASES с движком postgresql. Пароль и имя базы берут из окружения, а не из кода. Для статики на небольшом проекте достаточно collectstatic и отдачи каталога через Nginx; WhiteNoise пригодится, если отдельный веб-сервер не хочется настраивать.
Запуск через Gunicorn
Встроенный runserver предназначен только для разработки. В production приложение запускают несколько рабочих процессов Gunicorn, а Nginx принимает соединения, отдаёт статику и проксирует динамические запросы. Число воркеров подбирают по нагрузке, начиная с двух-трёх на одно ядро.
python manage.py check --deploy
python manage.py migrate --noinput
python manage.py collectstatic --noinput
gunicorn config.wsgi:application --bind 127.0.0.1:8001 --workers 3
location / {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ {
alias /srv/app/staticfiles/;
}
Службу удобно оформить через systemd: тогда Gunicorn перезапускается после сбоя и стартует вместе с системой. Логи направляют в journald или отдельные файлы с ротацией. После каждого обновления кода выполняют миграции, collectstatic и перезапуск службы — в таком порядке.
Диагностика и тесты
Команда check —deploy показывает потенциальные проблемы безопасности: включённый DEBUG, отсутствие HSTS, небезопасные cookie. Тесты запускают на отдельной базе, поэтому они не затрагивают рабочие данные. Если приложение отвечает 500, сначала смотрят журнал Gunicorn, затем воспроизводят запрос в shell.
python manage.py check --deploy
python manage.py showmigrations
python manage.py shell -c "from blog.models import Post; print(Post.objects.count())"
python manage.py test -v 2
Типичные ошибки: DisallowedHost при неверном ALLOWED_HOSTS, 403 из-за отсутствия CSRF-токена в форме, пустая страница статики после collectstatic. В последнем случае проверяют права на каталог staticfiles и совпадение пути в Nginx.
Чек-лист
- DEBUG выключен, SECRET_KEY и пароли — в переменных окружения.
- База PostgreSQL, миграции применены, резервная копия настроена.
- Статика собрана и отдаётся веб-сервером, а не Gunicorn.
- Настроены HTTPS, HSTS, безопасные cookie и заголовки прокси.
- Есть тесты ключевых сценариев и мониторинг ошибок.
Итог
Django даёт готовый фундамент для веб-приложения: модели, миграции, админку, формы и разумные настройки безопасности. Начинать стоит с виртуального окружения, одной модели и простого представления, а затем постепенно добавлять тесты, PostgreSQL и Gunicorn. Главное — не переносить в production настройки разработки и держать секреты вне репозитория.