2025, Oct 31 11:17

Почему сообщения Django исчезают после редиректа и как исправить

Сообщения Django пропадают после редиректа? Разбираем причину: вызов messages.get_messages очищает очередь. Решение и безопасная отладка представления.

Когда сообщения Django не отображаются после редиректа, это может сильно раздражать, особенно когда всё остальное выглядит корректным. Если ваше представление входа вызывает messages.error при неверных учётных данных, но предупреждение так и не появляется на странице логина, причина может быть в незаметной ловушке: сообщение стирается ещё до того, как шаблон успевает его получить.

Симптом

После отправки неверных данных приложение перенаправляет обратно на экран входа, но ожидаемого баннера с ошибкой нет. В логах сервера всё выглядит штатно: POST возвращает 302, затем выполняется GET страницы входа.

Проблемный пример кода

Проблема скрыта в логике представления, которое во время отладки заглядывает в очередь сообщений. Хотя фреймворк messages и подключение в шаблоне настроены правильно, одна строка заставляет Django преждевременно очистить хранилище сообщений.

from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib import messages
import logging
def auth_view(req):
    logging.debug(f"Method: {req.method}")
    if req.method == 'POST':
        uname = req.POST['username']
        pwd = req.POST['password']
        logging.debug(f"BODY: {req.POST}")
        acct = authenticate(req, username=uname, password=pwd)
        if acct is not None:
            login(req, acct)
            logging.debug("OK: authenticated, redirecting to home")
            return redirect('home')
        else:
            messages.error(req, "Invalid username or password. Please try again.")
            logging.debug("FAIL: invalid credentials, flagging error")
            logging.debug(f"Messages: {list(messages.get_messages(req))}")
            return redirect('login')
    else:
        logging.debug("Render login page")
        return render(req, "registration/login.html", {})

Почему так происходит

Вызов messages.get_messages(request) читает хранилище сообщений и заодно его опустошает. Так задумано: сообщения показываются один раз и затем очищаются. Когда этот вызов выполняется в представлении для отладки, он удаляет поставленное в очередь сообщение об ошибке ещё до завершения редиректа. В итоге шаблон рендерится с пустой коллекцией messages.

Решение

Удалите код, который опустошает хранилище сообщений. Продолжайте выставлять messages.error и делать редирект как прежде. Сообщение переживёт редирект и будет доступно в шаблоне.

from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib import messages
import logging
def auth_view(req):
    logging.debug(f"Method: {req.method}")
    if req.method == 'POST':
        uname = req.POST['username']
        pwd = req.POST['password']
        logging.debug(f"BODY: {req.POST}")
        acct = authenticate(req, username=uname, password=pwd)
        if acct is not None:
            login(req, acct)
            logging.debug("OK: authenticated, redirecting to home")
            return redirect('home')
        else:
            messages.error(req, "Invalid username or password. Please try again.")
            logging.debug("FAIL: invalid credentials, flagging error")
            return redirect('login')
    else:
        logging.debug("Render login page")
        return render(req, "registration/login.html", {})

Почему это важно

Отладочные вызовы, которые затрагивают stateful-API, могут незаметно менять поведение приложения. Фреймворк сообщений Django следует модели одноразового потребления, поэтому чтение очереди в рамках логирования фактически стирает те самые данные, которые вы ожидаете отобразить позже. Понимание этого избавит от часов поисков мнимых проблем в шаблонах или маршрутизации.

Ключевые выводы

Если сообщение, установленное перед редиректом, не появляется, проверьте, не перебираете ли вы очередь сообщений и не обращаетесь ли к ней в представлении. Установите сообщение, выполните редирект и позвольте шаблону его потребить. Этого достаточно, чтобы вернуть ожидаемый сценарий и сохранить стабильный UX при входе.

Статья основана на вопросе на StackOverflow от user31098877 и ответе Mahrez BenHamad.