В прошлом уроке мы установили Redis, Celery: Создание сайта на Django: Урок 50, асинхронные задачи, часть 1 (Установка Celery, Redis)
А в этом уроке мы создадим асинхронную задачу, поэтому давайте приступим к ее созданию.
Функцию отправки email подтверждения мы создавали в уроке: Создание сайта на Django: Урок 29, регистрация с подтверждением по электронной почте в Django
Поэтому, давайте создадим в папке "services" нашего модуля "system", файл с задачами: tasks.py
Должно получиться вот так:

modules/system/services/tasks.py
from celery import shared_task
from modules.system.services.email import send_activate_email_message
@shared_task
def send_activate_email_task(email):
"""
1. Получение из view регистрации
2. Отправка через функцию send_activate_email_message
"""
return send_activate_email_message(email)
Пояснение:
- Импортируем декоратор
@shared_task
, для регистрации наших задач. - Создаем функцию на получение задачи, получаемый аргумент будет email.
- Саму функцию мы будем вызывать во View.
- А возвращать результатом будем выполнение самой функции
send_activate_email_message
из урока 29.
Но я все таки напомню, как выглядит сама функцияsend_activate_email_message
:
modules/system/services/email.py
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)
Давайте поменяем методику вызова функции в RegisterCreateView
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) #edit
return super().form_valid(form)
На следующий код:
from modules.system.services.tasks import send_activate_email_task
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_task.delay(user.email) #edit
return super().form_valid(form)
Пояснение:
- Импортируем нашу задачу
send_activate_email_task
- Добавляем
delay
, чтобы пропустить выполнение кода и передать его на выполнение в Celery - Аргументом передаем email пользователя.
А теперь давайте зарегистрируем пользователя и посмотрим на выполнение задачи
Запущу Celery с помощью команды: celery --app=backend worker --loglevel=info --pool=solo
И как результат запуска, мы увидим, что наша задача send_activate_email_task
добавилась в пул задач Celery:
-------------- celery@Razilator-PC v5.2.7 (dawn-chorus)
--- ***** -----
-- ******* ---- Windows-10-10.0.22000-SP0 2022-09-25 19:38:01
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: backend:0x1f42b0cc130
- ** ---------- .> transport: redis://127.0.0.1:6379/0
- ** ---------- .> results: redis://127.0.0.1:6379/0
- *** --- * --- .> concurrency: 16 (solo)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. modules.system.services.tasks.send_activate_email_task
[2022-09-25 19:38:01,444: INFO/MainProcess] Connected to redis://127.0.0.1:6379/0
[2022-09-25 19:38:01,448: INFO/MainProcess] mingle: searching for neighbors
[2022-09-25 19:38:02,465: INFO/MainProcess] mingle: all alone
[2022-09-25 19:38:02,484: WARNING/MainProcess] C:\Users\Razilator\Desktop\Courses\App\venv\lib\site-packages\celery\fixups\django.py:203: UserWarning: Using settings.DEBUG leads to a memory
leak, never use this setting in production environments!
warnings.warn('''Using settings.DEBUG leads to a memory
[2022-09-25 19:38:02,485: INFO/MainProcess] celery@Razilator-PC ready.
А теперь я зарегистрирую пользователя:


После нажатия на кнопку регистрации, мы создали пользователя и отправили email активации, без какого-либо ожидания. В консоли Celery можно увидеть следующие действия:
[2022-09-25 19:40:50,228: INFO/MainProcess] Task modules.system.services.tasks.send_activate_email_task[3e78fcb1-b3c0-4d20-a113-6e781531bb6f] received
[2022-09-25 19:40:53,138: INFO/MainProcess] Task modules.system.services.tasks.send_activate_email_task[3e78fcb1-b3c0-4d20-a113-6e781531bb6f] succeeded in 2.906000000075437s: None
Ну и чтобы убедиться, вот письмо отправленное с помощью Celery и Redis:

А если мы зайдем в админ-панель Celery, то увидим нашу задачу со статусом выполнено (status: success):
