Наконец мы подошли к урокам, которые позволяют наращивать обычный функционал нашего блога какими-либо полезными функциями, как например подтверждение по email.
Напоминаю, что перед чтением этого урока вам необходимо настроить SMTP в Django для отправки электронных писем.
Урок:
И так, для активации по email я хочу написать функцию под названием send_activate_email_message. Для этого, я создам в папке services файл email.py

В этом файле я и создам необходимую функцию:
modules/system/services/email.py
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from modules.system.services.utils import account_activation_token
def send_activate_email_message(email):
user = User.objects.get(email=email)
current_site = Site.objects.get_current().domain
subject = 'Активация аккаунта на сайте Django блог'
message = render_to_string('modules/system/authenticated/email/activate-mail.html', {
'user': user,
'domain': current_site,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
return user.email_user(subject, message)
Пояснения:
- В функцию мы передаем email при регистрации.
- Получаем пользователя по данному email и отправляем ему письмо с токеном для активации.
Далее нам необходимо установить пакет six, для чего вы узнаете ниже:
pip install six
Collecting six
Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Installing collected packages: six
Successfully installed six-1.16.0
Отлично!
Но, нам нужно ещё написать функцию account_activation_token, для этого я напишу следующее в файле utils.py, что находится в модуле "system"
modules/system/services/utils.py
import six
from django.contrib.auth.tokens import PasswordResetTokenGenerator
class AppTokenGenerator(PasswordResetTokenGenerator):
"""
Генерация токенов для активации
"""
def _make_hash_value(self, user, timestamp):
return six.text_type(user.is_active) + six.text_type(user.pk) + six.text_type(timestamp)
account_activation_token = AppTokenGenerator()
Пояснения:
- Мы наследуемся от генератора токенов по восстановлению паролей.
- Импортируем необходимый функционал из установленного выше пакета six.
А теперь приступим к модернизации нашего представления RegisterCreateView, которое мы создавали в уроке 24.
modules\system\views\authenticated.py
from modules.system.services.email import send_activate_email_message
class RegisterCreateView(SuccessMessageMixin, CreateView):
"""
Представление регистрации на сайте с формой регистрации
"""
form_class = UserRegisterForm
success_url = reverse_lazy('home')
template_name = 'modules/system/authenticated/register.html'
success_message = 'Вы успешно зарегистрировались. Подтвердите ваш email адрес. Может попасть в папку СПАМ!'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = 'Регистрация на сайте'
return context
def form_valid(self, form):
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
send_activate_email_message(user.email)
return super().form_valid(form)
Пояснение:
- Я добавил в метод проверки form_valid, что при регистрации мы пользователю не даем активированный аккаунт, который дается по умолчанию.
- И в конце я добавляю функцию, которую мы создали, чтобы послать токен для активации на email.
- Изменил success_message = Вы успешно зарегистрировались. Подтвердите ваш email адрес. Может попасть в папку СПАМ!
Давайте создадим шаблон для письма activate-mail.html:
templates/modules/system/authenticated/email/activate-mail.html
{% autoescape off %}
Здравствуйте, {{ user.get_username }},
Для подтверждения регистрации на сайте Django блог, перейдите по ссылке ниже:
https://{{ domain }}{% url 'activate' uidb64=uid token=token %}
Спасибо, что решили присоединиться к нам!
Команда сайта Django блог
{% endautoescape %}
Напоминаю, что я использую вложенные папки, как декомпозицию и упорядоченность всех файлов и папок. Вы можете не пользоваться такой вложенностью, а создавать так, как вашей душе угодно.
Теперь мы должны создать представление обработки активации:
modules\system\views\authenticated.py
from django.utils.http import urlsafe_base64_decode
from django.utils.encoding import force_str
from django.views import View
from django.contrib.auth.models import User
from django.contrib.auth import login
from django.contrib import messages
from django.shortcuts import redirect
from modules.system.services.utils import account_activation_token
class ActivateAccountView(View):
"""
Активация аккаунта на сайте по токену
"""
def get(self, request, uidb64, token, *args, **kwargs):
try:
uid = force_str(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
login(request, user)
messages.success(request, 'Ваш аккаунт успешно подтвержден')
return redirect('home')
else:
messages.warning(request, 'Ссылка на активацию аккаунта устарела или не работает')
return redirect('home')
Пояснения:
- Перейдя по сгенерированной ссылки из письма мы обрабатываем ее, проверяя по токену.
- Активируем пользователя
- Авторизуем пользователя
- Выводим успешное сообщение о подтверждении аккаунта
- Редеректим его на главную
А теперь нужно подправить urls.py
modules/system/urls.py
from django.urls import path
from modules.system.views import ProfileView, ProfileEditView, RegisterCreateView, UserLoginView, \
UserPasswordChangeView, UserForgotPasswordView, UserPasswordResetConfirmView, UserLogoutView, ActivateAccountView
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('logout/', UserLogoutView.as_view(), name='logout'),
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'),
path('activate/<uidb64>/<token>/', ActivateAccountView.as_view(), name='activate'),
]
Пояснение:
- Импортировал ActivateAccountView
- Добавил activate/<uidb64>/<token>
Давайте попробуем зарегистрировать аккаунт и проверить активацию.


Теперь проверю свою почту. А вот и наше письмо активации:

Перейдем по ссылке:

Отлично, аккаунт подтвержден! Вот таким нетрудным способом можно реализовать систему активации на сайте. В интернете также много и других похожих вариантов, но этот проверенный временем.