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

Django: регистрация автора через стандартную форму

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

Учебная задача: Создать учётную запись через UserCreationForm и вернуть ошибки проверки.

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

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

Чтобы автор мог работать со своими заметками, приложение должно узнавать его между запросами. Начнём с создания учётной записи. Используем стандартную UserCreationForm, которая знает о модели пользователя и правильно сохраняет пароль. Не будем писать поле password в собственной таблице заметок и сравнивать строки вручную. Регистрация относится к системе пользователей, а связь с заметкой появится позже. Такое разделение помогает не смешивать личность автора с содержимым статьи.

В проекте уже подключены стандартные приложения auth, sessions и необходимые middleware. Их таблицы создаются системными миграциями во время самостоятельной подготовки среды. Наш каталог accounts содержит представление регистрации, но не определяет новую модель пользователя. Для данного курса стандартной модели достаточно. Если в реальном проекте нужен собственный пользователь, это решение желательно принимать до первой миграции, потому что поздняя замена влияет на связи и историю данных.

Два состояния одной страницы

GET-запрос показывает незаполненную форму. POST получает введённые значения и передаёт их в UserCreationForm(request.POST). Это два режима одного адреса с разными методами. Представление не сохраняет данные только потому, что они присутствуют в запросе. Сначала вызывается is_valid, и только успешная проверка открывает ветку save. При ошибке та же форма возвращается шаблону вместе с сообщениями, которые объясняют, почему сохранение не произошло.

В request.POST находится набор строковых значений полей. Его нельзя считать доверенным объектом пользователя. Форма переводит вход в проверенные значения согласно правилам и формирует собственные ошибки. Например, подтверждение пароля должно совпасть, а имя пользователя не должно конфликтовать с существующим. Часть правил задаётся формой, часть — моделью и валидаторами из настроек. Такая цепочка отличается от единственного HTML-атрибута required.

После сохранения выполняется redirect("login"). Регистрация не объявляется автоматическим входом: читателю предстоит подтвердить учётную запись обычной формой входа в следующей главе. Это выбранный процесс курса. Можно проектировать и другой сценарий, но его надо явно реализовать, а не ожидать от form.save. Создание строки пользователя и создание активной сессии — разные операции, как ранее создание модели и подключение её к странице.

Пароль и проверка

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

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

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

Шаблон и CSRF

Шаблон показывает form.as_p: поля с подписями и сообщения проверки. Это компактный исходный способ отображения, который позже можно заменить явной разметкой отдельных полей. Внутри формы есть {% csrf_token %}. При сохранении браузер передаёт токен, а middleware проверяет соответствие запроса ожидаемому состоянию. CSRF не доказывает право автора менять конкретную заметку; он защищает другую границу, связанную с происхождением запроса.

Не отключайте CSRF после первой ошибки 403, не разобравшись с причиной. Проверьте наличие токена внутри нужной формы, метод и используемый домен. Вход и регистрация должны обращаться к собственным согласованным адресам. Само по себе наследование base.html не переносит токен в произвольную форму: тег должен находиться в её содержимом, где HTML отправляет его вместе с остальными полями.

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

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

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

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

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

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

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

accounts/views.py

from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import redirect, render

def register(request):
    if request.method == "POST":
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("login")
    else:
        form = UserCreationForm()
    return render(request, "registration/register.html", {"form": form})

templates/registration/register.html

{% extends "base.html" %}
{% block content %}
<h1>Регистрация автора</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}<button>Создать учётную запись</button>
</form>
{% endblock %}

templates/registration/login.html

{% extends "base.html" %}
{% block content %}
<h1>Вход автора</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}<input type="hidden" name="next" value="{{ next }}">
<button>Войти</button>
</form>
{% endblock %}

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

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