如何自定义django rest身份验证密码重置电子邮件内容/模板

McL*_*ive 7 django django-rest-auth

在django rest_auth密码重置中,默认电子邮件内容如下所示:-

之所以收到此电子邮件,是因为您请求在localhost:8000重置用户帐户的密码。

请转到以下页面并选择一个新密码:

http:// localhost:8000 / api / reset / Kih / 89a-23809182347689312b123 /

您的用户名,以防万一您忘记了:测试

感谢您使用我们的网站!

本地主机:8000团队

如何自定义此电子邮件的内容?

Bri*_* K. 10

最近,我需要在我的一个项目中实施相同的操作,并且在任何地方都找不到完整的答案。

因此,我将解决方案留给将来有需要的任何人。

扩展mariodev的建议:

1. PasswordResetSerializer使用自定义save方法创建自己的方法。

PasswordResetSerializer从这里复制的基础:(https://github.com/Tivix/django-rest-auth/blob/v0.6.0/rest_auth/serializers.py#L102

yourproject_app/serializers.py

from django.contrib.auth.forms import PasswordResetForm
from django.conf import settings
from django.utils.translation import gettext as _
from rest_framework import serializers

###### IMPORT YOUR USER MODEL ######
from .models import ExampleUserModel

class PasswordResetSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password_reset_form_class = PasswordResetForm
    def validate_email(self, value):
        self.reset_form = self.password_reset_form_class(data=self.initial_data)
        if not self.reset_form.is_valid():
            raise serializers.ValidationError(_('Error'))

        ###### FILTER YOUR USER MODEL ######
        if not ExampleUserModel.objects.filter(email=value).exists():

            raise serializers.ValidationError(_('Invalid e-mail address'))
        return value

    def save(self):
        request = self.context.get('request')
        opts = {
            'use_https': request.is_secure(),
            'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),

            ###### USE YOUR TEXT FILE ######
            'email_template_name': 'example_message.txt',

            'request': request,
        }
        self.reset_form.save(**opts)
Run Code Online (Sandbox Code Playgroud)

2.连接自定义PasswordResetSerializer以覆盖默认值

yourproject_app/settings.py

REST_AUTH_SERIALIZERS = {
    'PASSWORD_RESET_SERIALIZER': 
        'yourproject_app.serializers.PasswordResetSerializer',
}
Run Code Online (Sandbox Code Playgroud)

3.将路径添加到您的自定义电子邮件文本文件所在的目录。 TEMPLATES

yourproject/settings.py

TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'yourproject/templates')],
        ...
    }
]
Run Code Online (Sandbox Code Playgroud)

4.编写自定义电子邮件(默认是从Django复制)

yourproject/templates/example_message.txt

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

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

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

{% blocktrans %}The {{ site_name }} team{% endblocktrans %}

{% endautoescape %}
Run Code Online (Sandbox Code Playgroud)

更新:此解决方案是为django-rest-auth(v0.6.0)的较旧版本编写的。从评论中可以看出,似乎对源软件包进行了一些更新,可以更轻松地处理自定义电子邮件模板。最好使用包中定义的方法,而不要像我的解决方案中那样覆盖它们。虽然曾经是必须的,但现在可能不再如此。

  • 谢谢,尽管使用最新版本的rest_auth,您只需要少量代码即可实现序列化程序。我可能会在将来发布我的解决方案。 (2认同)

M.V*_*oid 8

您可以继承PasswordResetSerializer和覆盖该get_email_options方法。例如:

from rest_auth.serializers import PasswordResetSerializer


class CustomPasswordResetSerializer(PasswordResetSerializer):
    def get_email_options(self):
        return {
            'subject_template_name': 'registration/password_reset_subject.txt',
            'email_template_name': 'registration/password_reset_message.txt',
            'html_email_template_name': 'registration/'
                                    'password_reset_message.html',
            'extra_email_context': {
                'pass_reset_obj': self.your_extra_reset_obj
            }
        }
Run Code Online (Sandbox Code Playgroud)

  • 我做了完全相同的事情,但对我不起作用。get_email_options 对我来说没有效果 (3认同)

mar*_*dev 7

您需要PASSWORD_RESET_SERIALIZER使用自定义save方法连接您自己的重置密码序列化程序 ( ) 。

(参考:https : //github.com/Tivix/django-rest-auth/blob/v0.6.0/rest_auth/serializers.py#L123

不幸的是,由于电子邮件选项的使用方式,您需要覆盖整个保存方法。我们将在下一个版本 (0.7.0) 中使其更加灵活


小智 7

一个简单的解决方案是在模板目录上创建:

-templates
   -registration
       password_reset_email.html
Run Code Online (Sandbox Code Playgroud)

有你想要的内容。Django rest-auth 使用 django.contrib.auth 模板。


Öze*_* S. 7

所以对于dj-rest-auth,我就是这样做的:

from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site
from django.urls.base import reverse
from allauth.account import app_settings
from allauth.account.adapter import get_adapter
from allauth.account.utils import user_pk_to_url_str, user_username
from allauth.utils import build_absolute_uri
from dj_rest_auth.forms import AllAuthPasswordResetForm
from dj_rest_auth.serializers import PasswordResetSerializer

class CustomAllAuthPasswordResetForm(AllAuthPasswordResetForm):
    def save(self, request, **kwargs):
        current_site = get_current_site(request)
        email = self.cleaned_data['email']
        token_generator = kwargs.get('token_generator',
                                     default_token_generator)

        for user in self.users:

            temp_key = token_generator.make_token(user)

            # save it to the password reset model
            # password_reset = PasswordReset(user=user, temp_key=temp_key)
            # password_reset.save()

            # send the password reset email
            path = reverse(
                'password_reset_confirm',
                args=[user_pk_to_url_str(user), temp_key],
            )
            url = build_absolute_uri(None, path) # PASS NONE INSTEAD OF REQUEST

            context = {
                'current_site': current_site,
                'user': user,
                'password_reset_url': url,
                'request': request,
            }
            if app_settings.AUTHENTICATION_METHOD != app_settings.AuthenticationMethod.EMAIL:
                context['username'] = user_username(user)
            get_adapter(request).send_mail('account/email/password_reset_key',
                                           email, context)
        return self.cleaned_data['email']

class CustomPasswordResetSerializer(PasswordResetSerializer):
    @property
    def password_reset_form_class(self):
        return CustomAllAuthPasswordResetForm

# settings.py
REST_AUTH_SERIALIZERS = {
    'PASSWORD_RESET_SERIALIZER':
    'api.users.api.serializers.CustomPasswordResetSerializer',
}
Run Code Online (Sandbox Code Playgroud)

通过传递Nonetobuild_absolute_uri而不是原始值request,它将采用django.contrib.sites模块 with中的值SITE_ID=1。因此,您在 Django 管理中定义的域现在将成为重置 URL 中的域。如果您想让密码重置 URL 指向您的前端(可能是在不同域上运行的 React 应用程序),这是有意义的。

编辑:我关于此问题的 PR 已合并,在下一个版本中,可以在您的设置中进行设置。查看文档以dj-rest-auth了解您需要设置哪个设置。


Ber*_*rah 6

如果您想使用 html 电子邮件模板,那么对 Brian 的回答的更新是添加

'html_email_template_name': 'account/email/example_message.html',

略低于

###### USE YOUR TEXT FILE ###### 'email_template_name': 'account/email/example_message.txt',

通过这种方式,您可以使用 html 模板发送电子邮件

您可以通过检查send_mailPasswordResetForm 类的方法来了解为什么会发生这种情况

class PasswordResetForm(forms.Form):
     email = forms.EmailField(label=_("Email"), max_length=254)

     def send_mail(self, subject_template_name, email_template_name,
              context, from_email, to_email, html_email_template_name=None):
              """
               Send a django.core.mail.EmailMultiAlternatives to `to_email`.
              """
             subject = loader.render_to_string(subject_template_name, context)
             # Email subject *must not* contain newlines
             subject = ''.join(subject.splitlines())
             body = loader.render_to_string(email_template_name, context)

             email_message = EmailMultiAlternatives(subject, body, from_email, [to_email])
             if html_email_template_name is not None:
                 html_email = loader.render_to_string(html_email_template_name, context)
                 email_message.attach_alternative(html_email, 'text/html')

             email_message.send()```
Run Code Online (Sandbox Code Playgroud)