如何自定义 django rest auth 密码重置电子邮件 content/template
How to customize django rest auth password reset email content/template
在 django rest_auth 密码重置中,默认电子邮件内容如下所示:-
You're receiving this email because you requested a password reset for your user account at localhost:8000.
Please go to the following page and choose a new password:
http://localhost:8000/api/reset/Kih/89a-23809182347689312b123/
Your username, in case you've forgotten: test
Thanks for using our site!
The localhost:8000 team
如何自定义这封邮件的内容?
您需要使用自定义的 save
方法连接您自己的重置密码序列化程序 (PASSWORD_RESET_SERIALIZER
)。
(参考:https://github.com/Tivix/django-rest-auth/blob/v0.6.0/rest_auth/serializers.py#L123)
不幸的是,由于 e-mail 选项的使用方式,您需要覆盖整个保存方法。我们将在下一个版本 (0.7.0)
中使其更加灵活
在模板文件夹中创建路径如下的目录
templates/admin/registration/
现在将 django/contrib/admin/templates/registration/ 中的所有文件复制到您刚刚创建的目录中。您可以在安装 django 的位置找到此目录。在linux,可以在这里找到
/usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/registration
您需要 root 权限才能访问它。
现在当您发送电子邮件时,将使用您刚刚复制到项目中的模板。
这个 link 可能会有帮助。有了它,我能够找到电子邮件模板的位置以及如何自定义它们。
您可以在页面底部找到信息
自定义电子邮件
http://www.sarahhagstrom.com/2013/09/the-missing-django-allauth-tutorial/#Customize_the_email_message
我最近需要在我的一个项目中实现同样的事情,但在任何地方都找不到彻底的答案。
所以我将我的解决方案留在这里供将来需要它的任何人使用。
扩展 mariodev 的建议:
1。子类 PasswordResetSerializer
并覆盖 save
方法。
yourproject_app/serializers.py
from django.conf import settings
from rest_auth.serializers import PasswordResetSerializer as _PasswordResetSerializer
class PasswordResetSerializer(_PasswordResetSerializer):
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)
2。配置 AUTH_USER_MODEL
yourproject/settings.py
###### USE YOUR USER MODEL ######
AUTH_USER_MODEL = 'yourproject_app.ExampleUser'
3。连接自定义 PasswordResetSerializer
以覆盖默认
yourproject/settings.py
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER':
'yourproject_app.serializers.PasswordResetSerializer',
}
4。将自定义电子邮件文本文件所在目录的路径添加到 TEMPLATES
yourproject/settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'yourproject/templates')],
...
}
]
5。编写自定义电子邮件消息(默认从 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 %}
更新: 此解决方案是为旧版本的 django-rest-auth (v0.6.0) 编写的。从评论中我可以看出,似乎对源包进行了一些更新,可以更轻松地处理开箱即用的自定义电子邮件模板。使用包中定义的方法总是比在我的解决方案中覆盖它们更好。虽然曾经是必需品,但可能不再是必需品了。
一个简单的解决方案是
创建模板目录:
-templates
-registration
password_reset_email.html
有你想要的内容。
Django rest-auth 使用 django.contrib.auth 模板。
如果您想使用 html 电子邮件模板,对 Brian 的回答的更新是添加
'html_email_template_name': 'account/email/example_message.html',
就在
下面
###### USE YOUR TEXT FILE ######
'email_template_name': 'account/email/example_message.txt',
通过这种方式,您可以使用 html 模板
发送电子邮件
您可以通过检查 PasswordResetForm class
的 send_mail
方法了解为什么会发生这种情况
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()```
您可以继承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
}
}
所以对于 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',
}
通过将 None
传递给 build_absolute_uri
而不是原来的 request
,它将采用您在 django.contrib.sites
模块中具有 SITE_ID=1
的值。因此,无论您在 Django 管理中定义为您的域,现在都将成为重置 URL 中的域。如果你想让密码重置 URL 指向你的前端,这很有意义,它可能是不同域上的 React 应用程序 运行。
编辑:
我关于此问题的 PR 已合并,在下一个版本中可以在您的设置中进行设置。查看 dj-rest-auth
的文档,了解您需要设置的设置。
在 django rest_auth 密码重置中,默认电子邮件内容如下所示:-
You're receiving this email because you requested a password reset for your user account at localhost:8000.
Please go to the following page and choose a new password:
http://localhost:8000/api/reset/Kih/89a-23809182347689312b123/
Your username, in case you've forgotten: test
Thanks for using our site!
The localhost:8000 team
如何自定义这封邮件的内容?
您需要使用自定义的 save
方法连接您自己的重置密码序列化程序 (PASSWORD_RESET_SERIALIZER
)。
(参考:https://github.com/Tivix/django-rest-auth/blob/v0.6.0/rest_auth/serializers.py#L123)
不幸的是,由于 e-mail 选项的使用方式,您需要覆盖整个保存方法。我们将在下一个版本 (0.7.0)
中使其更加灵活在模板文件夹中创建路径如下的目录
templates/admin/registration/
现在将 django/contrib/admin/templates/registration/ 中的所有文件复制到您刚刚创建的目录中。您可以在安装 django 的位置找到此目录。在linux,可以在这里找到
/usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/registration
您需要 root 权限才能访问它。
现在当您发送电子邮件时,将使用您刚刚复制到项目中的模板。
这个 link 可能会有帮助。有了它,我能够找到电子邮件模板的位置以及如何自定义它们。
您可以在页面底部找到信息 自定义电子邮件 http://www.sarahhagstrom.com/2013/09/the-missing-django-allauth-tutorial/#Customize_the_email_message
我最近需要在我的一个项目中实现同样的事情,但在任何地方都找不到彻底的答案。
所以我将我的解决方案留在这里供将来需要它的任何人使用。
扩展 mariodev 的建议:
1。子类 PasswordResetSerializer
并覆盖 save
方法。
yourproject_app/serializers.py
from django.conf import settings
from rest_auth.serializers import PasswordResetSerializer as _PasswordResetSerializer
class PasswordResetSerializer(_PasswordResetSerializer):
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)
2。配置 AUTH_USER_MODEL
yourproject/settings.py
###### USE YOUR USER MODEL ######
AUTH_USER_MODEL = 'yourproject_app.ExampleUser'
3。连接自定义 PasswordResetSerializer
以覆盖默认
yourproject/settings.py
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER':
'yourproject_app.serializers.PasswordResetSerializer',
}
4。将自定义电子邮件文本文件所在目录的路径添加到 TEMPLATES
yourproject/settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'yourproject/templates')],
...
}
]
5。编写自定义电子邮件消息(默认从 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 %}
更新: 此解决方案是为旧版本的 django-rest-auth (v0.6.0) 编写的。从评论中我可以看出,似乎对源包进行了一些更新,可以更轻松地处理开箱即用的自定义电子邮件模板。使用包中定义的方法总是比在我的解决方案中覆盖它们更好。虽然曾经是必需品,但可能不再是必需品了。
一个简单的解决方案是 创建模板目录:
-templates
-registration
password_reset_email.html
有你想要的内容。 Django rest-auth 使用 django.contrib.auth 模板。
如果您想使用 html 电子邮件模板,对 Brian 的回答的更新是添加
'html_email_template_name': 'account/email/example_message.html',
就在
下面###### USE YOUR TEXT FILE ######
'email_template_name': 'account/email/example_message.txt',
通过这种方式,您可以使用 html 模板
发送电子邮件您可以通过检查 PasswordResetForm class
的send_mail
方法了解为什么会发生这种情况
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()```
您可以继承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
}
}
所以对于 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',
}
通过将 None
传递给 build_absolute_uri
而不是原来的 request
,它将采用您在 django.contrib.sites
模块中具有 SITE_ID=1
的值。因此,无论您在 Django 管理中定义为您的域,现在都将成为重置 URL 中的域。如果你想让密码重置 URL 指向你的前端,这很有意义,它可能是不同域上的 React 应用程序 运行。
编辑:
我关于此问题的 PR 已合并,在下一个版本中可以在您的设置中进行设置。查看 dj-rest-auth
的文档,了解您需要设置的设置。