Перейти к содержанию

Django: вход, сессия и выход через POST

Оглавление курса · Скачать все состояния проекта.

Учебная задача: Подключить LoginView и LogoutView, отобразить пользователя и корректную форму выхода.

Входное состояние: Снимок lesson-11: регистрация создаёт пользователя, страница входа существует. Выходное состояние: Стандартный вход, условная шапка, logout через форму POST и CSRF. Эта глава продолжает «Редакционный стол» — небольшой сайт заметок. Нужны основы Python, HTML и устройство HTTP-запроса. Используем Python 3.12 и Django 5.2.18 LTS; номер ветки выбран для этой серии. Полный каталог lesson-12 в архиве содержит собственные настройки, шаблоны и историю миграций. При самостоятельном прохождении выберите один снимок и отдельную локальную базу; смешивание файлов разных глав меняет договор примера.

Исходники подготовлены редакционным чтением. Зависимости, миграции, сервер и команды работы с данными здесь не выполнялись. Все описанные ответы и изменения являются ожидаемыми, example_execution: not_run.

Созданная учётная запись ещё не означает, что приложение узнаёт автора на каждом запросе. Вход проверяет данные и связывает браузер с пользовательской сессией. Django предоставляет стандартные LoginView и LogoutView, поэтому в этой главе сосредоточимся на их подключении и поведении. Шапка сайта станет показывать имя текущего автора или ссылки регистрации и входа. Выход оформим POST-формой с CSRF-токеном, соответствующей выбранной версии Django.

Сессия помогает сохранять факт входа между запросами. В нашем проекте стандартное хранилище использует базу, а браузер получает идентификатор через cookie. Сам пароль не обязан передаваться на каждую страницу и не хранится как подпись ссылки. Middleware аутентификации восстанавливает пользователя и делает его доступным как request.user. Для неавторизованного посетителя это объект анонимного пользователя. Удобно проверять его признак, не сравнивая строки имён или адресов.

Подключение стандартных представлений

LoginView.as_view() создаёт обработчик для URLconf на основе класса представления. Шаблон ожидается по пути registration/login.html, который уже подготовлен. При GET он показывает форму, при POST проверяет учётные данные и выполняет предусмотренный процесс входа. Если пароль неверен, форма сообщает об ошибке без создания успешной сессии. Мы не добавляем собственную функцию прямого поиска пользователя по строковому паролю.

Настройка LOGIN_REDIRECT_URL указывает именованный список заметок. После обычного успешного входа автор попадает туда, если нет другого допустимого назначения. Параметр next позволяет вернуться к странице, ради которой потребовался вход. Шаблон сохраняет его скрытым полем. Не заменяйте стандартную обработку next произвольным перенаправлением на любой адрес из запроса: введённый пользователем путь необходимо оценивать, иначе приложение сможет отправлять его на нежелательные сайты.

Существование шаблона не является защитой адреса. Пока все прежние публичные экраны остаются открытыми согласно своей выборке. В следующей главе login_required будет требовать вход на странице собственных заметок. Именно тогда увидим сочетание защищённого представления и возвращения к нему после входа. Сейчас достаточно понять, где подключается класс, откуда он получает форму и какой результат ожидается при проверке пароля.

Пользователь в общем шаблоне

Контекстный процессор аутентификации делает user доступным для шаблонов при обычном render. В base.html проверяем user.is_authenticated. Если значение истинно, показываем имя и форму выхода. Если ложно, показываем ссылки входа и регистрации. Это управление интерфейсом. Оно не заменяет серверную проверку права на запись или просмотр конкретного объекта, потому что посетитель может запросить адрес без нажатия видимой ссылки.

В шапке используется user.username, а не полный набор полей пользователя. Отображение минимальной информации облегчает договор данных. Не передавайте в HTML служебные характеристики просто потому, что они присутствуют у объекта. Внутренний флаг суперпользователя, парольный хеш и детали сессии не являются нужной подписью приветствия. По мере развития кабинета можно добавить собственный профиль, сохраняя эту границу между идентичностью и публичным содержимым.

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

Почему выход является POST

Выход меняет состояние сессии. В выбранной ветке Django LogoutView обслуживает эту операцию через POST. Поэтому вместо обычной ссылки используем форму с action, полученным по имени logout, и токеном CSRF. Кнопка отправляет требуемый метод. Прямой GET по этому адресу не нужно трактовать как успешный выход. Если старый пример предлагает ссылку, при переносе следует проверить поведение версии, а не копировать его по памяти.

Для посетителя действие остаётся понятным: нажать «Выйти» в шапке. Техническое различие проявляется в запросе и контроле происхождения. После выхода ожидается перенаправление к списку согласно LOGOUT_REDIRECT_URL, а шапка снова предлагает вход. Не удаляем вручную любую cookie с похожим названием из JavaScript: стандартное представление знает, какую серверную сессию нужно завершить, и выполняет согласованную операцию.

Рассмотрите четыре ожидаемых случая: неправильный пароль, правильный вход, POST выхода, GET к адресу выхода. Они отличаются результатом и изменением сессии. Для самостоятельной работы объясните, почему скрытый элемент «Выйти» у анонимного пользователя не является механизмом проверки, а форма POST с токеном не является полномочием редактирования заметки. Следующая глава добавит связь author и выборку собственных черновиков; там вход станет предпосылкой предметной операции.

Разбор связи файлов

Cookie с идентификатором сессии и объект пользователя в серверном запросе относятся к одной цепочке, но не являются одинаковыми данными. Браузер отправляет cookie, стандартные механизмы Django определяют сессию и пользовательскую личность. Шаблон получает уже подготовленный request.user через подключённый контекст. Не нужно читать cookie вручную в каждой странице.

Значение next определяет возвращение после входа. Стандартный LoginView проверяет допустимость адреса; сохранение такого поведения предпочтительнее собственного безусловного перенаправления на любую присланную строку. Вход должен возвращать человека в нужный раздел, а не превращаться в способ отправить его на произвольный внешний сайт.

Выход завершает действие сессии, но не удаляет учётную запись и её заметки. Поэтому автор может снова войти теми же данными. Это различие станет заметным, когда появится личный список: содержимое хранится в базе независимо от конкретного посещения. Для самостоятельного разбора опишите ожидаемую шапку до входа, после входа и после выхода. Затем объясните, какие серверные проверки потребуются для изменения материала во всех трёх состояниях.

Полные файлы этого шага

Следующие файлы показаны полностью. Остальные согласованные файлы находятся в том же снимке архива; переносите весь каталог при выборе исходного состояния.

desk/urls.py

from django.contrib import admin
from django.urls import include, path

from accounts.views import register
from django.contrib.auth.views import LoginView, LogoutView

urlpatterns = [path("accounts/register/", register, name="register"),
               path("accounts/login/", LoginView.as_view(), name="login"),
               path("accounts/logout/",
                   LogoutView.as_view(),
                   name="logout"),
                   path("admin/",
                   admin.site.urls),
                   path("notes/",
                   include("notes.urls"))]

from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

templates/base.html

{% load static %}
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>
{% block title %}Редакционный стол{% endblock %}
</title>
<link rel="stylesheet" href="{% static 'notes/desk.css' %}">
</head>
<body>
<header>
<a href="{% url 'notes:list' %}">Редакционный стол</a>
{% if user.is_authenticated %}
<span>{{ user.username }}</span>
<form action="{% url 'logout' %}" method="post">
{% csrf_token %}
<button>Выйти</button>
</form>
{% else %}
<a href="{% url 'login' %}">Войти</a> <a href="{% url 'register' %}">Регистрация</a>
{% endif %}
</header>
<main>
{% block content %}{% endblock %}
</main>
</body>
</html>

Документация и исходники

Механизм этой главы описан в официальной документации Django 5.2. При самостоятельной проверке сначала сопоставьте маршрут, представление и состояние данных, затем сравните результат с указанным ожидаемым поведением. Архив учебного проекта содержит все шестнадцать самостоятельных этапов и договор эксплуатации.