Создание сайта на Django: Урок 27, форма восстановления пароля
avatar
7 | (offline)
❤️‍🔥Notehunter Developer
Добавлено:
Категория: Руководства «Django»
Комментариев: 0

В этом уроке по Django 4.1 мы поговорим о создании формы восстановления пароля с запросом токена на ваш зарегистрированный email.

Руководство по настройке email в Django из 26 урока

Создадим необходимые формы для ввода email и восстановления пароля:

modules/system/forms/authenticated.py

from django.contrib.auth.forms import PasswordResetForm

class UserForgotPasswordForm(PasswordResetForm):
    """
    Запрос на восстановление пароля
    """

    def __init__(self, *args, **kwargs):
        """
        Обновление стилей формы
        """
        super().__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].widget.attrs.update({
                'class': 'form-control',
                'autocomplete': 'off'
            })

Пояснения:

  • Наследуемся от PasswordResetForm
  • Настраиваем Bootstrap стили

И создаем форму для установки пароля:

from django.contrib.auth.forms import SetPasswordForm

class UserSetNewPasswordForm(SetPasswordForm):
    """
    Изменение пароля пользователя после подтверждения
    """

    def __init__(self, *args, **kwargs):
        """
        Обновление стилей формы
        """
        super().__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].widget.attrs.update({
                'class': 'form-control',
                'autocomplete': 'off'
            })

Пояснения:

  • Ранее в уроке по изменению пароля мы уже наследовались от SetPasswordForm, но в этот раз это сделано для гостей!

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

modules/system/views/authenticated.py

from modules.system.forms.authenticated import 
UserForgotPasswordForm
from django.contrib.auth.views import PasswordResetView
from django.urls import reverse_lazy
from django.contrib.messages.views import SuccessMessageMixin


class UserForgotPasswordView(SuccessMessageMixin, PasswordResetView):
    """
    Представление по сбросу пароля по почте
    """
    form_class = UserForgotPasswordForm
    template_name = 'modules/system/authenticated/password-reset.html'
    success_url = reverse_lazy('home')
    success_message = 'Письмо с инструкцией по восстановлению пароля отправлено на ваш email'
    subject_template_name = 'modules/system/authenticated/email/password-subject-reset-mail.html'
    email_template_name = 'modules/system/authenticated/email/password-reset-mail.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Сброс пароля на сайте'
        return context

Пояснения:

  • Это мы создали представление для ввода email адреса.
  • Импортировали нашу форму UserForgotPasswordForm
  • И наследуемся от PasswordResetView, встроенного представления в Django
  • Указываем в email_template_name/subject_template_name шаблон на инструкцию
  • template_name - наша форма для ввода email
  • success_url  - перенаправление после успеха
  • success_message  - уведомление от SuccessMessageMixin об успешной отправке

А теперь сразу создадим представление для установки пароля:

from django.contrib.auth.views import PasswordResetConfirmView

from modules.system.forms.authenticated import UserSetNewPasswordForm                                  

from django.urls import reverse_lazy

from django.contrib.messages.views import SuccessMessageMixin


class UserPasswordResetConfirmView(SuccessMessageMixin, PasswordResetConfirmView):                      
    """                                                                                                 
    Представление установки нового пароля                                                               
    """                                                                                                 
    form_class = UserSetNewPasswordForm                                                                 
    template_name = 'modules/system/authenticated/password-set-new.html'                                
    success_url = reverse_lazy('home')                                                                  
    success_message = 'Вы успешно восстановили пароль, теперь вы можете авторизоваться с новым паролем' 
                                                                                                        
    def get_context_data(self, **kwargs):                                                               
        context = super().get_context_data(**kwargs)                                                    
        context['title'] = 'Установить новый пароль'                                                    
        return context                                                                                  

Пояснения:

  • Наследуемся от PasswordResetConfirmView встроенного в Django
  • UserSetNewPasswordForm используем нашу форму для установки нового пароля

А теперь создадим необходимые ссылки!

from django.urls import path

from modules.system.views import ProfileView, ProfileEditView, RegisterCreateView, UserLoginView, \
    UserPasswordChangeView, UserForgotPasswordView, UserPasswordResetConfirmView

urlpatterns = [
    path('user/edit/', ProfileEditView.as_view(), name='profile-edit'),
    path('user/<str:slug>/', ProfileView.as_view(), name='profile'),
    path('register/', RegisterCreateView.as_view(), name='register'),
    path('login/', UserLoginView.as_view(), name='login'),
    path('password-change/', UserPasswordChangeView.as_view(), name='password-change'),
    path('password-reset/', UserForgotPasswordView.as_view(), name='password-reset'),
    path('set-new-password/<uidb64>/<token>/', UserPasswordResetConfirmView.as_view(), name='password-reset-confirm'),
]

Пояснения:

  • Добавил наши представления UserForgotPasswordView и UserPasswordResetConfirmView
  • <uidb64>/<token> - это то, что придет на наш email. Необходимый токен для подтверждения пользователя для смены пароля.

А теперь создадим необходимые шаблоны как для форм, так и для email:

templates/modules/system/authenticated/password-reset.html

{% extends 'main.html' %}

{% block content %}
    <div class="card mb-3 border-0 nth-shadow">
        <div class="card-body">
            <div class="card-title nth-card-title">
                <h4>Восстановление пароля на сайте</h4>
            </div>
            <form method="post">
                {% csrf_token %}
                {{ form.as_p }}
                <button type="submit" class="btn btn-dark mt-2">Восстановить пароль</button>
            </form>
        </div>
    </div>
{% endblock %}

Теперь для установки пароля:

templates/modules/system/authenticated/password-set-new.html

{% extends 'main.html' %}
{% block content %}
    <div class="card mb-3 border-0 nth-shadow">
        <div class="card-body">
            <div class="card-title nth-card-title">
                <h4>Установить новый пароль</h4>
            </div>
            <form method="post">
                {% csrf_token %}
                {{ form.as_p }}
                <button type="submit" class="btn btn-dark mt-2">Подтвердить</button>
            </form>
        </div>
    </div>
{% endblock %}

Отлично. Шаблоны настроили, теперь шаблон для письма

В папочке templates/modules/system/authenticated/ я создам папку email, а внутри нее password-reset-mail.html

templates/modules/system/authenticated/email/password-reset-mail.html

{% autoescape off %}
    
    Вы получили это электронное письмо, потому что запросили сброс пароля для своей учетной записи пользователя на {{ site_name }}.

	Перейдите на следующую страницу и выберите новый пароль:
	{% block reset_link %}
	    {{ protocol }}://{{ domain }}{% url 'password-reset-confirm' uidb64=uid token=token %}
	{% endblock %}
	Ваше имя пользователя, если вы забыли: {{ user.get_username }}

	Спасибо за использование нашего сайта!

	The {{ site_name }} team

{% endautoescape %}

И для темы письма:

templates/modules/system/authenticated/email/password-subject-reset-mail.html

Письмо о восстановлении пароля на сайте Notehunter

Но, нам нужно ещё кое-что сделать. Перейдем в backend/settings.py и добавим в INSTALLED_APPS - 'django.contrib.sites' и SITE_ID = 1

backend/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sites',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mptt',
    'modules.blog.apps.BlogConfig',
    'modules.system.apps.SystemConfig',
]

SITE_ID = 1

И применим миграции в базу данных:

(venv) PS C:\Users\Razilator\Desktop\Courses\App\backend> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions, sites, system
Running migrations:
  Applying sites.0001_initial... OK
  Applying sites.0002_alter_domain_unique... OK
(venv) PS C:\Users\Razilator\Desktop\Courses\App\backend>

А далее, идем в админку в новую категорию "Сайты" и изменяем сайт example.com

Сохраняем, без каких либо http, https://!

Перехожу по ссылке неавторизованным пользователем: http://127.0.0.1:8000/s/password-reset/

Нажимаю восстановить:

Захожу на свою почту и вижу письмо:

И перейдя по ссылке, устанавливаем пароль в форме установки пароля:

И получаем успех об установленном пароле

Отлично, у нас все получилось как нужно! Теперь пользователи смогут восстанавливать свои пароля посредством запроса на свой email адрес. 

Комментарии к статье 0
Комментариев нет
Форма добавления комментария (необходима регистрация)