MTV, структура проекта, безопасные settings, WSGI и ASGI
Django — веб-фреймворк с готовыми инструментами для маршрутизации, работы с базой данных, HTML-форм, аутентификации, админки и защиты от типовых веб-атак. Его сильная сторона не в том, что каждый компонент подходит любому проекту, а в том, что компоненты согласованы между собой.
В этой главе важно получить карту фреймворка. Детали моделей, представлений и шаблонов мы разберём дальше.
Целевая версия: примеры рассчитаны на Django 5.2 LTS и 6.0, Python 3.12+.
Когда браузер обращается к Django, запрос проходит несколько этапов:
Django называет свою организацию кода MTV: Model, Template, View. Это не строгая архитектура всего приложения, а удобное описание основных ролей.
| Компонент | За что отвечает |
|---|---|
| Model | Структура хранимых данных, связи и запросы через ORM |
| Template | Представление HTML без доступа к произвольному Python-коду |
| View | Граница HTTP: принимает request и возвращает response |
| URLconf | Связывает URL с view |
Бизнес-правило не обязано жить во view или model. В сложном проекте его часто выделяют в сервисную функцию или доменный объект. Главное — не дублировать правило в нескольких HTTP-обработчиках.
Проект хранит общую конфигурацию и корневые точки входа. Приложение группирует связанную функциональность: например, блог, заказы или биллинг.
python -m pip install "Django>=5.2,<6.1"
django-admin startproject config .
python manage.py startapp blogПосле этого важны две группы файлов:
manage.py
config/
├── settings.py
├── urls.py
├── wsgi.py
└── asgi.py
blog/
├── admin.py
├── apps.py
├── migrations/
├── models.py
├── tests.py
└── views.pymanage.py устанавливает настройки проекта и передаёт управление Django-команде. wsgi.py и asgi.py создают application callable для соответствующего протокола. Они не являются серверами сами по себе.
Приложение подключают через его AppConfig:
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"blog.apps.BlogConfig",
]BlogConfig описывает конфигурацию приложения: его имя, тип primary key по умолчанию и startup hooks. Это не URL namespace. Простая строка "blog" тоже допустима, если Django может найти конфигурацию автоматически.
Настройки — обычный Python-модуль, но секреты и параметры окружения не должны быть зашиты в код. Production-конфигурация должна завершать запуск с ошибкой, если обязательный секрет отсутствует.
# config/settings/base.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
DEBUG = False
ALLOWED_HOSTS = [
host.strip()
for host in os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")
if host.strip()
]Здесь три вызова .parent нужны потому, что файл находится в config/settings/base.py. Если структура проекта другая, уровень нужно пересчитать, а не копировать механически.
Development-настройки могут иметь отдельный заведомо локальный ключ:
# config/settings/dev.py
from .base import * # noqa: F403
DEBUG = True
SECRET_KEY = "development-only-key-not-for-production"
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"При запуске выбирают конкретный модуль:
DJANGO_SETTINGS_MODULE=config.settings.dev python manage.py runserverРазделять settings необязательно: небольшой проект может использовать один файл и переменные окружения. Разделение полезно, когда настройки окружений действительно различаются.
WSGI — синхронный интерфейс между Python-приложением и сервером. Он подходит большинству обычных Django-приложений. ASGI поддерживает асинхронный request stack и долгоживущие соединения.
# WSGI
gunicorn config.wsgi:application
# ASGI
uvicorn config.asgi:applicationAsync view может работать и под WSGI, но Django создаст отдельный event loop для запроса и не даст преимуществ полностью асинхронного стека. Для высокой конкуренции долгих I/O-запросов нужен ASGI-сервер и совместимый middleware stack.
Сам get_asgi_application() обрабатывает HTTP. WebSocket требует ASGI-маршрутизации, обычно через Django Channels или другой ASGI-компонент. Поддержка HTTP/2 зависит от сервера и reverse proxy, а не только от наличия asgi.py.
Важно: стандартный
manage.py runserverиспользует WSGI development server. Интеграция Daphne может заменить его ASGI-вариантом, но это отдельная настройка.
Начнём без модели, чтобы увидеть только HTTP-слой.
# blog/views.py
from django.http import JsonResponse
def health(request):
return JsonResponse({"status": "ok"})# blog/urls.py
from django.urls import path
from .views import health
app_name = "blog"
urlpatterns = [
path("health/", health, name="health"),
]# config/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("blog/", include("blog.urls")),
]Запрос к /blog/health/ проходит через корневой URLconf, URLconf приложения и функцию health. app_name создаёт namespace для reverse URL lookup; AppConfig к этому namespace отношения не имеет.
Не нужно запоминать весь список manage.py. Достаточно понимать группы операций:
python manage.py check
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py test
python manage.py shell
python manage.py runservercheck проверяет конфигурацию, но не заменяет тесты. Перед production-деплоем используют также python manage.py check --deploy с production settings.
django.conf.urls.url() удалён в Django 4.0; современные проекты используют path() и re_path() из django.urls.settings.py. Это не ошибка само по себе.AppConfig URL namespace.SECRET_KEY со значением по умолчанию.runserver нельзя использовать в production.Далее: Модели: Основы