Cat

Django 33. Сброс пароля пользователя

В этом посте реализуем функционал сброса пароля пользователем.

Все статьи

Icon Link

Дополнительные материалы

Icon Link

Реклама

Icon Link
Сайт на Django proDream 20 Октябрь 2023 Просмотров: 1137

В посте "Django 13. Сброс пароля", мы уже писали сброс пароля, но то было для панели администратора. 
В этом посте, реализуем сброс пароля для обычных пользователей.

Также для корректной работы, необходимо указать почтовый сервис.
Как его настроить я описывал в посте "Django 12. Настройка отправки почты".
А в постах "Docker 5.1 Почтовый сервер на Docker Mailserver - настройка домена" и "Docker 5.2 Почтовый сервер на Docker Mailserver - настройка и запуск" рассказывал как запустить свой почтовый сервер.

Для реализации сброса пароля, можно пойти простым или сложным путём.

Простой путь, это использовать уже встроенные в Django представления и формы, именно так мы и сделали в прошлый раз.
Достаточно в файле urls.py указать паттерны:

from django.contrib.auth import views as auth_views


path('password-reset/',  
auth_views.PasswordResetView.as_view(template_name='users/pass_reset.html'),  
     name='password-reset'),  
path('password_reset_confirm/<uidb64>/<token>/',  
auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'),  
     name='password_reset_confirm'),  
path('password_reset_complete/',   auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset_complete.html'),  
     name='password_reset_complete'),  
path('password-reset/done/',  auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset_done.html'),  
     name='password_reset_done'),

 

Указав собственные шаблоны. 
Однако, в нашем случае, уже есть сброс пароля для админа и они будут конфликтовать.
Можно вовсе убрать сброс пароля для админ и оставить общий, но куда интереснее переопределить представления.

Этим и займёмся.

 

Переопределение форм.

Начнём с переопределения форм для того, чтобы добавить в них поддержку стилей из Bootstrap.

Откроем файл forms.py в директории приложения user_app.

Тут нам надо переопределить две формы: форму ввода электронной почты для сброса и форму ввода нового пароля.
Мы не будем переписывать их полностью, а просто наследуемся от них и изменим стандартные поля.

 

Код форм:

from django.contrib.auth import password_validation  
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm


class CustomPasswordResetForm(PasswordResetForm):  
    email = forms.EmailField(  
        label="Email",  
        max_length=254,  
        widget=forms.EmailInput(  
            attrs={'class': 'form-control',  
                   'placeholder': 'Введите Email',  
                   "autocomplete": "email"}  
        )  
    )  


class CustomSetPasswordForm(SetPasswordForm):  
    error_messages = {  
        "password_mismatch": "Пароли не совпадают"  
    }  
    new_password1 = forms.CharField(  
        label='Новый пароль',  
        widget=forms.PasswordInput(  
            attrs={'class': 'form-control',  
                   'placeholder': 'Введите новый пароль',  
                   "autocomplete": "new-password"}  
        ),  
        strip=False,  
        help_text=password_validation.password_validators_help_text_html(),  
    )  
    new_password2 = forms.CharField(  
        label='Подтверждение нового пароля',  
        strip=False,  
        widget=forms.PasswordInput(  
            attrs={'class': 'form-control',  
                   'placeholder': 'Подтвердите новый пароль',  
                   "autocomplete": "new-password"}  
        ),  
    )

 

В первой форме CustomPasswordResetForm, унаследованной от PasswordResetForm, мы переопределили только поле email.
Добавив класс из Bootstrap и прописав текст внутри поля.

Во второй форме CustomSetPasswordForm, унаследованной от SetPasswordForm, мы переопределили два поля new_password1 и new_password2, а так же прописали сообщение, если пароли не совпадают в поле error_messages.

 

Переопределение представлений.

Откроем файл views.py в директории приложения user_app.

Тут мы создадим два собственных представления:

  • CustomPasswordResetView - представление страницы, где пользователь вводит электронную почту для сброса. Наследуемся от PasswordResetView.
  • CustomUserPasswordResetConfirmView - представление страницы на которую пользователь перейдёт из письма для ввода нового пароля. Наследуемся от PasswordResetConfirmView.

 

Код представлений.

from django.contrib.auth.views import PasswordResetView, PasswordResetConfirmView
from user_app.forms import CustomPasswordResetForm, CustomSetPasswordForm


class CustomPasswordResetView(PasswordResetView):  
    template_name = 'user_app/password_reset.html'  
    email_template_name = 'user_app/password_reset_email.html'  
    form_class = CustomPasswordResetForm  
    success_url = reverse_lazy('user_app:password_reset_done')  


class CustomUserPasswordResetConfirmView(PasswordResetConfirmView):  
    template_name = 'user_app/password_reset_confirm.html'  
    success_url = reverse_lazy('user_app:password_reset_complete')  
    form_class = CustomSetPasswordForm

 

В этих представлениях, переопределим следующие поля:

  • template_name - файл шаблона.
  • email_template_name - файл шаблона для отправки по электронной почте. Только в представлении CustomPasswordResetView.
  • form_class - класс с формой.
  • success_url - путь, куда будет перенаправлен пользователь после отправки формы.

 

Шаблоны страниц.

В директории с шаблонами приложения user_app, необходимо создать пять файлов:

  • password_reset.html - первая страница сброса пароля. На этой странице пользователь вводит свой email.
  • password_reset_done.html - вторая страница сброса пароля. На этой странице сообщаем пользователю, что письмо со ссылкой для сброса было отправлено на email.
  • password_reset_confirm.html - третья страница сброса пароля. На этой странице пользователь вводит новый пароль.
  • password_reset_complete.html - четвёртая и последняя страница сброса пароля. На этой странице сообщаем, что пароль был изменён.
  • password_reset_email.html - страница шаблона для электронной почты. Код страницы взят из стандартного Django-шаблона, с одним лишь изменением - ссылкой на которую перейдёт пользователь из письма. Если этот файл не изменить, то в письме будет ссылка на сброс пароля администратора, а нам не нужно, что бы пользователи знали адрес панели администратора.

 

password_reset.html и password_reset_confirm.html.

Стандартный шаблон формы:

<form method="POST">  
    {% csrf_token %}  
    {{ form.as_p }}  
    <button type="submit" class="btn btn-danger mt-3">Запросить новый пароль</button>  
</form>

 

Различия только в тексте кнопки. Вообще можно сделать один файл и передавать текст кнопки через контекст.

 

password_reset_done.html.

В этом шаблоне сообщаем, что письмо отправлено и добавляем кнопку возврата на главную страницу.

<div class="container mt-3">  
    <h2>Ссылка для смены пароля отправлена на вашу почту.</h2>  
    <a href="{% url 'blog:index' %}" class="btn btn-danger mt-3">Вернуться на главную</a>  
</div>

 

password_reset_complete.html.

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

<div class="container mt-3">  
    <h2>Вы успешно обновили пароль</h2>  
    <p>Ваш пароль заменен на новый!</p>  
    <a href="{% url 'user_app:login' %}" class="btn btn-danger mt-3">Войти</a>  
    <a href="{% url 'blog:index' %}" class="btn btn-danger mt-3">Вернуться на главную</a>  
</div>

 

password_reset_email.html.

Изменённый стандартный шаблон письма со ссылкой для восстановления пароля. 
Изменить необходимо имя URL-шаблона в этой строке:

{{ protocol }}://{{ domain }}{% url 'user_app:password_reset_confirm' uidb64=uid token=token %}

 

Код шаблона:

{% load i18n %}{% autoescape off %}  
{% blocktranslate %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktranslate %}  

{% translate "Please go to the following page and choose a new password:" %}  
{% block reset_link %}  
{{ protocol }}://{{ domain }}{% url 'user_app:password_reset_confirm' uidb64=uid token=token %}  
{% endblock %}  
{% translate 'Your username, in case you’ve forgotten:' %} {{ user.get_username }}  

{% translate "Thanks for using our site!" %}  

{% blocktranslate %}The {{ site_name }} team{% endblocktranslate %}  

{% endautoescape %}

 

URL-паттерны страниц.

Откроем файл urls.py и в список urlpatterns добавим новые паттерны:

from django.contrib.auth import views as auth_views


path('password-reset/', views.CustomPasswordResetView.as_view(), name='password-reset'),  
path('password_reset_confirm/<uidb64>/<token>/',  
     views.CustomUserPasswordResetConfirmView.as_view(),  
     name='password_reset_confirm'),  
path('password_reset_complete/',  
auth_views.PasswordResetCompleteView.as_view(template_name='user_app/password_reset_complete.html'),  
     name='password_reset_complete'),  
path('password-reset/done/',  
auth_views.PasswordResetDoneView.as_view(template_name='user_app/password_reset_done.html'),  
     name='password_reset_done'),

 

Последний штрих.

Осталось добавить ссылку на страницу сброса пароля в шаблон страницы входа.

Откроем файл login.html и добавим следующую строчку где-нибудь внизу:

Забыли пароль? <a href="{% url 'user_app:password-reset' %}">Сбросить пароль</a>

 

Готово. Теперь пользователь сможет сбросить свой пароль.

 

Автор

    Нет комментариев

    Реклама