Почему нельзя просто запустить Django на дефолтном сервере
Что проверяют
Отличаете ли вы среду разработки от боевой и понимаете ли, из чего состоит развёртывание Python-приложения: сервер приложений, обратный прокси, присмотр за процессами, раздача статики.
Как отвечать
runserver в документации прямо помечен как инструмент разработки: он не проходил аудит безопасности и не рассчитан на нагрузку. Конкретно не хватает вот чего.
Нет присмотра за процессом: упал, и сайт лежит до ручного перезапуска. Нет перезапуска воркеров по памяти и по числу обработанных запросов, нет плавной выкатки без обрыва соединений. Зато есть автоперезагрузчик, который следит за файлами и тратит ресурсы впустую.
Нет защиты от медленного клиента: при прямом подключении к серверу приложений один клиент, отдающий тело запроса по байту, занимает воркер целиком. Поэтому впереди ставят обратный прокси, он буферизует запрос и ответ, держит TLS и раздаёт статику, которую runserver при выключенном DEBUG отдавать вообще перестаёт.
Рабочая связка: обратный прокси, за ним gunicorn или uvicorn под управлением systemd либо в контейнере, статика через прокси или whitenoise, DEBUG выключен, ключ и пароли из окружения, аккуратный ALLOWED_HOSTS. Число воркеров считают от ядер, помня, что каждый держит собственные соединения к базе.
Где спотыкаются
Повторяют миф, что runserver обрабатывает один запрос за раз. Он многопоточный по умолчанию, и довод, построенный на этом, интервьюер собьёт одной фразой. Настоящие причины это отсутствие присмотра за процессом, аудита безопасности и защиты от медленных клиентов.
Второе: считают, что достаточно заменить runserver на gunicorn и выставить его наружу. С синхронными воркерами без прокси возвращаются те же медленные клиенты, а статику всё равно кто-то должен отдавать.
Третье: путают WSGI и ASGI. Асинхронные вью, вебсокеты и долгие соединения по WSGI не поедут, для них нужен ASGI-сервер, и тип воркера выбирают осознанно, а не по первой найденной команде запуска.