如何使用Celery(无需第三方包)发送Django的密码重置邮件?

问题描述 投票:0回答:3

首先,我知道这个问题之前已经被回答过here,它使用第三方包django-celery-email,但我试图弄清楚如何在不依赖任何第三方的情况下完成这样的工作图书馆。

所以我需要使用 Celery 异步发送密码重置电子邮件。

我的

forms.py
文件如下所示:

from django import forms
from accounts.tasks import send_mail
from django.contrib.auth.forms import PasswordResetForm as PasswordResetFormCore


class PasswordResetForm(PasswordResetFormCore):
    email = forms.EmailField(max_length=254, widget=forms.TextInput(
        attrs={
            'class': 'form-control',
            'id': 'email',
            'placeholder': 'Email'
        }
    ))

    def send_mail(self, subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name=None):
        """
        This method is inherating Django's core `send_mail` method from `PasswordResetForm` class
        """
        super().send_mail(subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name)

我正在尝试通过 Celery

send_mail
类的
PasswordResetForm
方法发送邮件。我的意思是用
Celery
调用 super().send_mail(...)。我的
Celery
send_mail 文件中还有一个
tasks.py
函数,我试图将
super().send_mail
方法作为参数传递以从那里调用它。

现在我的

tasks.py
文件看起来像这样:

from __future__ import absolute_import, unicode_literals


@shared_task
def send_mail():
    pass

我使用

RabbitMQ
作为消息代理以及
Celery

python django django-forms rabbitmq celery
3个回答
2
投票

好的,我已经找到了一个有效的解决方案。这是我的解决方案。

我已经改变了

forms.py
如下

from django import forms
from accounts.tasks import send_mail
from django.contrib.auth.forms import PasswordResetForm as PasswordResetFormCore


class PasswordResetForm(PasswordResetFormCore):
    email = forms.EmailField(max_length=254, widget=forms.TextInput(
        attrs={
            'class': 'form-control',
            'id': 'email',
            'placeholder': 'Email'
        }
    ))

    def send_mail(self, subject_template_name, email_template_name, context, 
                  from_email, to_email, html_email_template_name=None):
        context['user'] = context['user'].id

        send_mail.delay(subject_template_name=subject_template_name, 
                        email_template_name=email_template_name,
                        context=context, from_email=from_email, to_email=to_email,
                        html_email_template_name=html_email_template_name)

改变后的

tasks.py
如下

from __future__ import absolute_import, unicode_literals
from accounts.models import User
from django.contrib.auth.forms import PasswordResetForm


@shared_task
def send_mail(subject_template_name, email_template_name, context,
              from_email, to_email, html_email_template_name):
    context['user'] = User.objects.get(pk=context['user'])

    PasswordResetForm.send_mail(
        None,
        subject_template_name,
        email_template_name,
        context,
        from_email,
        to_email,
        html_email_template_name
    )

1
投票

与上一个类似,但以精简的方式

表格.py

"""users/forms.py"""
from django.contrib.auth.forms import PasswordResetForm
from users.tasks import send_reset_password_email_async

class CustomPasswordResetForm(PasswordResetForm):
    """
    Extend Auth Form for adding support to Async email using Celery
    """
    # keys -> email, domain, site_name, uid, user, token, protocol
    context = args[2]
    context['user'] = context['user'].pk 
    send_reset_password_email_async.delay(*args, **kwargs)

任务.py

"""users/tasks.py"""
from users.models import User
from celery import shared_task
from django.contrib.auth.forms import PasswordResetForm

@shared_task
def send_reset_password_email_async(*args, **kwargs):
    """
    Description
    -----------
    - User must be restore from None to object.
    - Send the reset password email as async task
    """
    # Restoring user
    context = args[2]
    context['user'] = User.objects.get(pk=context['user'])
    PasswordResetForm.send_mail(None, *args, **kwargs)

最后使用开头扩展的形式 url.py

"""proj/urls.py"""
from django.urls import path, include,

urlpatterns = [
    # ...
        path(
        'password_reset/',
        auth_views.PasswordResetView.as_view(
            form_class=CustomPasswordResetForm,  # <-- async email support
            # ...
        ),
        name='password_reset'
    ),
    # ...
]

已测试!


0
投票

我的解决方案:

用户/表单.py

from django.contrib.auth.forms import PasswordResetForm
from django.template import loader

from core.tasks import async_send_mail


class PasswordResetFormWithAsyncEmail(PasswordResetForm):
    def send_mail(
        self,
        subject_template_name,
        email_template_name,
        context,
        from_email,
        to_email,
        html_email_template_name=None,
    ):
        subject = loader.render_to_string(subject_template_name, context)
        subject = ''.join(subject.splitlines())
        body = loader.render_to_string(email_template_name, context)
        if html_email_template_name is not None:
            html_email = loader.render_to_string(html_email_template_name,
                                                 context)
        else:
            html_email = None
        return async_send_mail.delay(
            subject=subject,
            message=body,
            from_email=from_email,
            recipient_list=[to_email],
            html_message=html_email,
        )

用户/urls.py

from django.contrib.auth.views import PasswordResetView
from django.urls import path

from users.forms import PasswordResetFormWithAsyncEmail


urlpatterns = [
    path(
        'password_reset/',
        PasswordResetView.as_view(
            template_name='users/password_reset_form.html',
            form_class=PasswordResetFormWithAsyncEmail,
        ),
        name='password_reset_form'
    ),
]

核心/tasks.py

from celery import shared_task, Task
from django.core.mail import send_mail


class BaseTaskWithRetry(Task):
    autoretry_for = (Exception, KeyError)
    retry_kwargs = {'max_retries': 5}
    retry_backoff = True
    retry_jitter = True


@shared_task(bind=True, base=BaseTaskWithRetry)
def async_send_mail(
    self,
    subject,
    message,
    from_email,
    recipient_list,
    html_message=None,
):
    return send_mail(
        subject=subject,
        message=message,
        from_email=from_email,
        recipient_list=recipient_list,
        html_message=html_message,
        fail_silently=False,
    )
© www.soinside.com 2019 - 2024. All rights reserved.