Курс по Django: https://stepik.org/a/183363
Архив проекта: 62_sitewomen.zip
На прошлом занятии
мы с вами вручную реализовали механизм авторизации пользователей на сайте. На
этом перепишем его с использованием стандартных классов, поставляемых фреймворком
Django. Они следующие:
- LoginView – класс
представления для авторизации пользователей;
- LogoutView – класс
представления для выхода пользователя из системы;
- AuthenticationForm – класс формы
обработки аутентификации пользователя.
Начнем с класса LoginView, которым
заменим функцию login_user() следующим образом:
class LoginUser(LoginView):
form_class = AuthenticationForm
template_name = 'users/login.html'
extra_context = {'title': "Авторизация"}
Вам здесь должны
быть знакомы все используемые атрибуты. И, обратите внимание, атрибуту form_class мы присваиваем
стандартный класс формы AuthenticationForm фреймворка Django. Если здесь
прописать наш текущий класс формы:
form_class = LoginUserForm
то получим
ошибку, так как наше новое представление LoginUser ожидает форму с
набором определенных методов и атрибутов, чтобы в связке с ней обрабатывать
процесс авторизации. Конечно, мы можем вручную создать нужную форму, но куда
проще или напрямую воспользоваться уже имеющейся для этих целей:
form_class = AuthenticationForm
Либо, при
необходимости, расширить ее дочерним классом. Пока оставим наше представление в
таком виде. Подключим его к маршруту login в файле users/urls.py:
urlpatterns = [
path('login/', views.LoginUser.as_view(), name='login'),
path('logout/', views.logout_user, name='logout'),
]
Запустим
веб-сервер и перейдем в форму авторизации. Как видите, все отображается и при
вводе логина и пароля происходит автоматическое перенаправление в профайл по URL-адресу:
http://127.0.0.1:8000/accounts/profile/
Но нам это не
нужно. Изменим адрес перенаправления, переопределив метод get_success_url() в классе LoginUser:
def get_success_url(self):
return reverse_lazy('home')
Теперь, при
авторизации будем попадать на главную страницу. Тот же самый эффект можно
получить, определив константу:
в файле settings.py пакета
конфигурации sitewomen. Но лучше здесь
указывать имена маршрутов:
LOGIN_REDIRECT_URL = 'home'
Вообще, в файле
конфигурации settings.py можно
прописывать следующие параметры:
- LOGIN_REDIRECT_URL – задает URL-адрес, на
который следует перенаправлять пользователя после успешной авторизации;
- LOGIN_URL – определяет URL-адрес, на
который следует перенаправить неавторизованного пользователя при попытке
посетить закрытую страницу сайта;
- LOGOUT_REDIRECT_URL – задает URL-адрес, на
который перенаправляется пользователь после выхода.
Улучшение формы авторизации
Как видите,
класс представления LoginView берет на себя значимую часть
стандартной работы по авторизации пользователя. И дополнительно он формирует
сообщения об ошибках, которые передает в форму, при неверно заполненных данных.
Давайте в этом убедимся. Для этого откроем шаблон формы login.html и вывод полей
формы будем делать через цикл:
<div class="form-error">{{ form.non_field_errors }}</div>
{% for f in form %}
<p ><label class="form-label" for="{{ f.id_for_label }}">{{f.label}}: </label>{{ f }}</p>
<div class="form-error">{{ f.errors }}</div>
{% endfor %}
Обратите
внимание, вначале не забываем делать отображение общих ошибок коллекции form.non_field_errors.
Обновим страницу
авторизации и введем неверную пару логин/пароль. Увидим отображение ошибки. Эта
ошибка, была автоматически сформирована классом представления LoginView. И это очень
удобно. Обработку всех стандартных ситуаций фреймворк Django берет на себя.
Но мы бы хотели
еще улучшить и сам класс формы. Для этого в файле users/forms.py существующий
класс LoginUserForm унаследуем от класса AuthenticationForm следующим образом:
class LoginUserForm(AuthenticationForm):
username = forms.CharField(label='Логин', widget=forms.TextInput(attrs={'class': 'form-input'}))
password = forms.CharField(label='Пароль', widget=forms.PasswordInput(attrs={'class': 'form-input'}))
Обновим форму
авторизации и видим, что в целом все работает. Обратите внимание, что в этой
форме поля должны называться именно так, как прописаны: username и password. Вообще, они
должны соответствовать стандартной модели пользователя User фреймворка Django. Поэтому, как
вариант, мы могли бы определить этот же класс LoginUserForm следующим
образом:
class LoginUserForm(AuthenticationForm):
class Meta:
model = get_user_model()
fields = ['username', 'password']
Мы здесь
получаем модель User с помощью стандартной функции get_user_model(). Это
рекомендуемая практика на случай изменения модели. Тогда в программе ничего
дополнительно менять не придется. Также указали отображать в форме поля username и password. Именно они
необходимы для аутентификации пользователя по БД.
В общем случае,
можно комбинировать мета-описание и отдельные атрибуты. Что я и сделаю:
class LoginUserForm(AuthenticationForm):
username = forms.CharField(label='Логин', widget=forms.TextInput(attrs={'class': 'form-input'}))
password = forms.CharField(label='Пароль', widget=forms.PasswordInput(attrs={'class': 'form-input'}))
class Meta:
model = User
fields = ['username', 'password']
Так форма
выглядит понятнее по своей логике работы.
Параметр next
Последний штрих,
который мы сделаем в форме – это добавим скрытое поле с именем next в шаблон login.html следующим
образом:
<input type="hidden" name="next" value="{{ next }}" />
Что это за
параметр? Дело в том, что теперь мы можем в URL-адресе формы
авторизации дополнительно прописывать этот параметр next, например, так:
http://127.0.0.1:8000/users/login/?next=/addpage/
Он содержит URL-адрес страницы,
на которую следует сделать перенаправление после успешной авторизации. В данном
случае, мы попадаем на страницу добавления статей. Причем, этот параметр next имеет более
высокий приоритет, чем параметр LOGIN_REDIRECT_URL, прописанный в пакете
конфигурации.
Зачем вообще
может понадобиться этот параметр? Возможно, вы замечали, как выбираете товар в
интернет-магазине и для его помещения в корзину необходима авторизация. Форма
ввода логина/пароля сразу появляется на экране и после корректного ввода, вы
сразу попадаете в корзину. Как вы думаете, как сайт догадался вас перенаправить
именно в корзину? Да, сработал аналог параметра next для
перенаправления на нужную страницу сайта. И то же самое могло произойти, когда
товар уже в корзине, а для оформления заказа понадобилась авторизация. Тогда
посетитель перенаправляется уже не в корзину, а на оформление заказа. То есть,
иногда нам нужна не какая-то определенная страница после авторизации, а
произвольная, адрес которой можно сохранить в параметре next. Это очень
удобно и в фреймворк Django этот функционал уже встроен.
Класс LogoutView
Последний класс,
который мы рассмотрим на этом занятии – это LogoutView. С его помощью
можно заменить функцию представления logout_user(). Если нам достаточно стандартного
поведения, то класс LogoutView можно сразу связать с нужным маршрутом
(в файле users/urls.py):
urlpatterns = [
path('login/', views.LoginUser.as_view(), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
]
А функцию logout_user()
просто убрать. Переходим на сайт, нажимаем «Выйти» и попадаем на несуществующую
страницу:
http://127.0.0.1:8000/users/logout/
Как нам задать
другой адрес для выхода? Для этого можно воспользоваться константой LOGOUT_REDIRECT_URL, прописав ее в
файле settings.py, например, так:
LOGOUT_REDIRECT_URL = 'home'
Теперь мы будем
выходить на главную страницу сайта.
Курс по Django: https://stepik.org/a/183363