Пользователи не могут самостоятельно зарегистрироваться на проекте Yatube: в приложении django.contrib.auth нет готовой страницы регистрации. Сделаем сами, вариантов нет.Вот план работы:
- На основе встроенного класса UserCreationForm напишем класс формы CreationForm; свяжем этот класс с моделью User.
- На основе Generic Views CreateView создадим view-класс SignUp, он будет связан с формой CreationForm.
- Создадим HTML-шаблон, он примет объект
form
из view-класса SignUp. - Добавим вызов view-класса SignUp в urls.py.
Всё почти как с формой для книг в предыдущем уроке, только класс для создания формы — другой.
Создание формы на основе класса UserCreationForm
С технической точки зрения «процесс регистрации нового пользователя» — это создание нового объекта модели User. Пользователь отправляет через форму свои данные, после проверки эти данные передаются в модель User и сохраняются в базе.
Регистрация пользователя — стандартная и востребованная процедура, и авторы Django сделали за нас основную работу. В модуле django/contrib/auth/forms.py для создания формы регистрации заготовлен класс UserCreationForm (наследник встроенного класса ModelForm). На основе этого класса создаётся форма регистрации.
# ... django/contrib/auth/forms.py
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
# ...
В исходном коде класса UserCreationForm видно, что форма создаётся на основе модели User. Класс UserCreationForm (как и любые наследники класса ModelForm) считывает свойства модели и на их основе создаёт поля формы.Создадим класс CreationForm, наследника класса UserCreationForm. Классу ModelForm он будет приходиться внуком: ModelForm → UserCreationForm → CreationForm
Класс CreationForm можно было бы и не создавать, а напрямую подключить встроенный класс UserCreationForm из пакета django.contrib.auth, но нужно внести изменения в работу предустановленного класса: хочется вывести на страницу не все поля, а лишь те, которые нужны для регистрации именно на нашем сайте.В Django принято хранить формы в отдельном файле, и мы последуем этому правилу.
В приложении users cоздайте файл forms.py и добавьте в него импорты и код нового класса формы:
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model
User = get_user_model()
# создадим собственный класс для формы регистрации
# сделаем его наследником предустановленного класса UserCreationForm
class CreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
# укажем модель, с которой связана создаваемая форма
model = User
# укажем, какие поля должны быть видны в форме и в каком порядке
fields = ('first_name', 'last_name', 'username', 'email')
Согласно рекомендациям разработчиков Django, к модели User лучше обращаться через функцию get_user_model(). Это нужно для того, чтобы разработчик без труда мог переопределить модель, которая будет хранить данные пользователей. По умолчанию это модель User, она создаётся при установке Django. Но если эта модель по каким-то причинам не подходит — можно унаследоваться от базовой модели User, расширить или изменить новую модель, описать её свойства и зарегистрировать её в системе в качестве модели пользователей.
Функция get_user_model() обращается именно к той модели, которая зарегистрирована в качестве основной модели пользователей в конфиге проекта.
Если разработчик заменит эту модель на собственную, вносить изменения по всему проекту ему не придётся, будет достаточно изменить лишь одно значение в конфиге. Но это только в том случае, если он повсюду предусмотрительно применял get_user_model()
Наследственность в классе Meta
В классе CreationForm
описан вложенный класс Meta: он унаследован от родительских классов. В нём настраивается форма, и именно в нём мы переопределяем некоторые параметры.
Конструкция class Meta(UserCreationForm.Meta)
описывает обычное наследование, только наследуется не основной класс, а вложенный:
# наследуется класс UserCreationForm:
class CreationForm(UserCreationForm):
# наследуется класс Meta, вложенный в класс UserCreationForm:
class Meta(UserCreationForm.Meta):
# ...
В результате класс Meta, вложенный в класс CreationForm, унаследует все ключи UserCreationForm.Meta
, но теперь их можно переопределить.
Копировать целиком код класса Meta из UserCreationForm
в свой код было бы не лучшей идеей, такой подход грозит проблемами: если в следующей версии Django в UserCreationForm.
Meta
добавят что-то новое — придётся в своём коде искать и исправлять несовместимости. Наследование лишено этого недостатка.
Обратите внимание: в исходном классе
UserCreationForm
в классе Meta
есть строка
model = User
Ссылка идёт прямо на модель User, без посредства функции get_user_model(). В своём коде, в классе CreationForm, мы переопределяем переменную model
, присвоив ей значение get_user_model() (передав его через переменную User
).
Отображение формы
Создайте в файле users/views.py view-класс SignUp, унаследовав его от Generic ViewCreateView
# users/views.py
# Импортируем CreateView, чтобы создать ему наследника
from django.views.generic import CreateView
# Функция reverse_lazy позволяет получить URL по параметрам функции path()
# Берём, тоже пригодится
from django.urls import reverse_lazy
# Импортируем класс формы, чтобы сослаться на неё во view-классе
from .forms import CreationForm
class SignUp(CreateView):
form_class = CreationForm
# После успешной регистрации перенаправляем пользователя на главную.
success_url = reverse_lazy('posts:index')
template_name = 'users/signup.html'
- form_class — из какого класса взять форму
- success_url — куда перенаправить пользователя после успешной отправки формы
- template_name — имя шаблона, куда будет передана переменная
form
с объектом HTML-формы. Всё это чем-то похоже на вызов функцииrender()
во view-функции.
Теперь в шаблон users/signup.html будет отправлена форма с полями, описанными в классе CreationForm*.* После заполнения этой формы пользователь будет переадресован на страницу, для которой в urls.py указано имя name='posts:index'
. Данные, отправленные через форму, будут переданы в модель User и сохранены в БД.
Добавление URL страницы регистрации в urls.py
Теперь добавьте в файл users/urls.py
адрес страницы регистрации пользователей:
# users/urls.py
from django.urls import path
from . import views
urlpatterns = [
...
# Полный адрес страницы регистрации - auth/signup/,
# но префикс auth/ обрабатывается в головном urls.py
path('signup/', views.SignUp.as_view(), name='signup')
]
Готово всё, кроме шаблона users/signup.html
.
Добавление шаблона
В templates/users создайте файл signup.html
и добавьте в него код для отображения формы:
<!-- templates/users/signup.html -->
{% extends "base.html" %}
{% block title %}Зарегистрироваться{% endblock %}
{% block content %}
<form method="post" action="{% url 'users:signup' %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Зарегистрироваться">
</form>
{% endblock %}
Всё!
Зайдите на страницу http://127.0.0.1:8000/auth/signup/. Там должна отобразиться приблизительно такая форма:
Готово, всё работает, хоть и выглядит не очень нарядно. Следующий урок посвятим наведению красоты.
В шаблоне есть «form.as_p» — откуда берется переменная form, если мы ее нигде не указывали?