Поддерживает ли Django password_reset шаблоны электронной почты html?

#python #django

#python #django

Вопрос:

Мне кажется, django поддерживает только простые текстовые сообщения для электронных писем со сбросом пароля из коробки. Как я могу использовать шаблоны html для этой цели?

Ответ №1:

Вот как вы можете выполнить переопределение:

urls.py

 url(r'^user/password/reset/

views.py

 from django.contrib.auth.views import password_reset as django_password_reset
from YOUR_APP.forms import CustomPasswordResetForm

def password_reset(*args, **kwargs):
    """
        Overriding the Email Password Resert Forms Save to be able to send HTML email
    """
    kwargs['password_reset_form'] = CustomPasswordResetForm
    return django_password_reset(*args, **kwargs)
 

form.py

 from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.tokens import default_token_generator

class CustomPasswordResetForm(PasswordResetForm):
    """
        Overriding the Email Password Resert Forms Save to be able to send HTML email
    """
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
             use_https=False, token_generator=default_token_generator, request=None, email_subject_name='registration/password_reset_subject.txt', **kwargs):
        from django.core.mail import EmailMultiAlternatives
        from django.utils.html import strip_tags
        from django.template.loader import render_to_string
        from django.contrib.sites.models import get_current_site
        from django.utils.http import int_to_base36

        for user in self.users_cache:
            if not domain_override:
                current_site = get_current_site(request)
                site_name = current_site.name
                domain = current_site.domain
            else:
                 site_name = domain = domain_override

            c = {
                'email': user.email,
                'domain': domain,
                'site_name': site_name,
                'uid': int_to_base36(user.id),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': use_https and 'https' or 'http',
            }
            render = render_to_string(email_template_name, c)
            render_subject = render_to_string(email_subject_name, c)

            msg = EmailMultiAlternatives(render_subject, strip_tags(render), None, [user.email])
            msg.attach_alternative(render, "text/html")
            msg.send()
 

Комментарии:

1. Я получаю эту ошибку: ошибка атрибута в объекте /user/password/reset/ 'CustomPasswordResetForm' не имеет атрибута 'users_cache'. Вы допустили ошибку? Должен ли я использовать какую-либо другую функцию вместо users_cache()? Что делают другие.

Ответ №2:

Вы можете переопределить save метод django.contrib.auth.forms.PasswordResetForm и передать новую форму в качестве аргумента для password_reset просмотра.

Ответ №3:

Электронное письмо с сбросом пароля HTML с изображениями в Django 3.0

Обзор

  1. Создайте три шаблона:
    • password_reset_email.html
    • password_reset_email.txt
    • password_reset_subject.txt
  2. Переопределение django.contrib.auth.forms.PasswordResetForm путем создания подкласса.
  3. Переопределите аргументы для PasswordResetForm.save() , чтобы указать на ваши пользовательские шаблоны.
  4. Переопределите PasswordResetForm.send_email() , если вы хотите вставлять изображения в HTML-сообщение электронной почты.
  5. Установите django.contrib.auth.views.PasswordResetView.form_class для использования ваш новый PasswordResetForm подкласс.

1. Создайте три шаблона

  • В вашем каталоге шаблонов Django создайте подкаталог с именем "регистрация".
  • В разделе "шаблоны / регистрация" добавьте три шаблона:
    • password_reset_email.html
    • password_reset_email.txt
    • password_reset_subject.txt
  • Шаблон электронной почты HTML должен быть хорошо структурированным HTML-документом. Смотрите пример ниже.
  • Шаблон "* .txt" должен быть простым шаблоном (без HTML). Смотрите пример ниже.

Пример password_reset_email.html

 {% autoescape off %}
<!DOCTYPE html>

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1"/>

        <title>Password Reset</title>

        <style type="text/css">
            
            body {
                background-color: #ffffff;
                font-size: 14px;
                line-height: 16px;
                font-family: PTSansRegular,Arial,Helvetica,sans-serif;
                height: 100%;
                margin: 0;
                padding: 0;
                border: 0;
                outline: 0;
            }

            a.button {
                background-color: #007bff;
                border-color: #007bff;
                border-radius: 5px;
                color: #ffffff;
                cursor: pointer;
                display: inline-block;
                font-size: 15px;
                line-height: 18px;
                font-weight: bold;
                font-family: PTSansRegular,Arial,Helvetica,sans-serif;
                padding: 7px;
                text-align: center;
                text-decoration: none;
                white-space: nowrap;
                width: 150px;
            }

            .center {
                text-align: center
            }

            .container {
                min-height: 100%;
                min-width: 650px;
                position: relative;
                width: 100%;
            }

            p {
                text-align:left
            }

            table {
                margin: auto;
                width:650px;
            }

            td {
                padding-right: 14px;
                padding-left: 14px;
            }
        </style>
    </head>

    <body>

    <div class="container">

    <!-- BEGIN EMAIL -->
    <table align="center" border="0" cellpadding="0" cellspacing="0">
    <tr>
        <td>
            <p>Hello {{ user.get_username }},</p>

            <p>A request has been received to change the password for your account.</p>

            <p class="center">
                <a target="_blank" class="button"
                        href="{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}">
                    Reset Password
                </a>
            </p>

            <p>This link can only be used once. If you need to reset your password again, please visit
            <a href="{{ protocol }}://{{domain}}">{{ site_name }}</a> and request another reset.</p>

            <p>If you did not make this request, please contact us immediately at
            <a href="mailto: YOUR_SUPPORT_EMAIL">YOUR_SUPPORT_EMAIL</a>.</p>

            <p>Sincerely,</p>
            <p>The YOUR_COMPANY_NAME Team</p>
        </td>
    </tr>
    </table>
    <!-- END EMAIL -->

    <table class="spacer">
        <tr><td class="spacer">amp;nbsp;</td></tr>
    </table>

    <!-- BEGIN FOOTER -->
    <table align="center">
        <tr>
            <td>
                <p class="center"><img src="cid:logo" /></p>
            </td>
        </tr>
        <tr>
            <td class="center">YOUR_ADDRESS_AND_OR_COPYRIGHT</td>
        </tr>
    </table>
    <!-- END FOOTER -->
    </div>

    </body>
</html>
{% endautoescape %}
 

Пример password_reset_email.txt

 {% autoescape off %}
Hello {{ user.get_username }},

A request has been received to change the password for your account. Click the link below to reset your password.

{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}">

This link can only be used once. If you need to reset your password again, please visit
{{ protocol }}://{{domain}}">{{ site_name }} and request another reset.

If you did not make this request, please contact us immediately at YOUR_SUPPORT_EMAIL.

Sincerely,

The YOUR_COMPANY_NAME Team



YOUR_COMPANY_NAME
YOUR_ADDRESS_AND_OR_COPYRIGHT
{% endautoescape %}
 

2. Override django.contrib.auth.forms.PasswordResetForm

  • In your Django app directory, create a module named "forms.py".
  • Create a subclass of django.contrib.auth.forms.PasswordResetForm and override the save() method.

Example: forms.py

 class CustomPasswordResetForm(PasswordResetForm):
    """Override the default Django password-reset form to send the password reset 
    email using both HTML and plain text.
    """

    def save(
        self,
        domain_override: Optional[str] = None,
        subject_template_name: str = PASSWORD_RESET_SUBJECT_TEMPLATE,
        email_template_name: str = PASSWORD_RESET_TEXT_TEMPLATE,
        use_https: Optional[bool] = None,
        token_generator: PasswordResetTokenGenerator = default_token_generator,
        from_email: Optional[str] = FROM_EMAIL,
        request: Optional[WSGIRequest] = None,
        html_email_template_name: Optional[str] = PASSWORD_RESET_HTML_TEMPLATE,
        extra_email_context: Optional[Dict[str, str]] = None
    ) -> None:
        """Generate a one-use only link for resetting password and email it to 
        the user.

        Args:
            domain_override: Optional; Domain name to use in the email message 
                template that overrides the actual domain from which the email is 
                sent. Defaults to None.
            subject_template_name: Optional; Warning: this argument is overridden 
                by the global variable ``PASSWORD_RESET_SUBJECT_TEMPLATE``.
            email_template_name: Optional; Warning: this argument is overridden by 
                the global variable ``PASSWORD_RESET_TEXT_TEMPLATE``.
            use_https: Optional; If True, use HTTPS, otherwise use HTTP. Defaults 
                to False. Note that if the password reset HTTP request is received 
                via HTTPS, `use_https` will be set to True by the auth view.
            token_generator: Optional; Strategy object used to generate and check 
                tokens for the password reset mechanism. Defaults to an instance 
                of ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
            from_email: Optional; Warning: this argument is overridden by the 
                global variable``FROM_EMAIL``.
            request: Optional; The HttpRequest object. Defaults to None.
            html_email_template_name: Warning: this argument is overridden by the 
                global variable ``PASSWORD_RESET_HTML_TEMPLATE``.
            extra_email_context: Optional; Key-value pairs to add to the context 
                dictionary used to render the password reset email templates. 
                    Defaults to None.
        """
        email_template_name = PASSWORD_RESET_TEXT_TEMPLATE
        from_email = FROM_EMAIL
        html_email_template_name = PASSWORD_RESET_HTML_TEMPLATE
        subject_template_name = PASSWORD_RESET_SUBJECT_TEMPLATE

        email = self.cleaned_data["email"]
        if not domain_override:
            current_site = get_current_site(request)
            site_name = current_site.name
            domain = current_site.domain
        else:
            site_name = domain = domain_override
        UserModel = get_user_model()
        email_field_name = UserModel.get_email_field_name()  # type: ignore

        for user in self.get_users(email):
            user_email = getattr(user, email_field_name)
            context = {
                'email': user_email,
                'domain': domain,
                'site_name': site_name,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': 'https' if use_https else 'http',
                **(extra_email_context or {}),
            }

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

 

3. Override the arguments for PasswordResetForm.save() to point to your custom templates.

  • In your "forms.py" module, add global variables as follows:

Example forms.py

 from typing import Final


# Constants for sending password-reset emails.
LOGO_FILE_PATH: Final[str] = "img/logo.png"
LOGO_CID_NAME: Final[str] = "logo"
PASSWORD_RESET_FORM_TEMPLATE: Final[str] = "registration/password_reset_form.html"
PASSWORD_RESET_HTML_TEMPLATE: Final[str] = "registration/password_reset_email.html"
PASSWORD_RESET_TEXT_TEMPLATE: Final[str] = "registration/password_reset_email.txt"
PASSWORD_RESET_SUBJECT_TEMPLATE: Final[str] = "registration/password_reset_subject.txt"
SUPPORT_EMAIL: Final[str] = "YOUR_SUPPORT_EMAIL_ADDRESS"
FROM_EMAIL: Final[str] = f"YOUR_COMPANY_NAME Support <{SUPPORT_EMAIL}>"
 

4. Override PasswordResetForm.send_email() if you want to embed images in the HTML email.

Example: forms.py

 def get_as_mime_image(image_file_path: str, cid_name: str) -> MIMEImage:
    """Fetch an image file and return it wrapped in a ``MIMEImage`` object for use 
    in emails.

    After the ``MIMEImage`` has been attached to an email, reference the image in 
    the HTML using the Content ID.

    Example:

    If the CID name is "logo", then the HTML reference would be:

    <img src="cid:logo" />

    Args:
        image_file_path: The path of the image. The path must be findable by the 
            Django staticfiles app.
        cid_name: The Content-ID name to use within the HTML email body to 
            reference the image.

    Raises:
        FileNotFoundError: If the image file cannot be found by the staticfiles app.

    Returns:
        MIMEImage: The image wrapped in a ``MIMEImage`` object and the Content ID 
        set to ``cid_name``.
    """
    paths = finders.find(image_file_path)
    if paths is None:
        raise FileNotFoundError(f"{image_file_path} not found in static files")

    if isinstance(paths, list):
        final_path = paths[0]
    else:
        final_path = paths
    with open(final_path, 'rb') as f:
        image_data = f.read()

    mime_image = MIMEImage(image_data)
    mime_image.add_header("Content-ID", f"<{cid_name}>")
    return mime_image


class CustomPasswordResetForm(PasswordResetForm):
    """Override the default Django password-reset form to send the password reset email using both HTML and plain text.
    """
    def send_mail(
        self,
        subject_template_name: str,
        email_template_name: str,
        context: Dict[str, str],
        from_email: Optional[str],
        to_email: str,
        html_email_template_name: Optional[str] = None,
    ) -> None:
        """Send a ``django.core.mail.EmailMultiAlternatives`` to ``to_email``.

        This method also attaches the company logo, which can be added to the 
        email HTML template using:

        <img src="cid:logo" />

        Args:
            subject_template_name: Path of the template to use as the email 
                subject.
            email_template_name: Path of the template to use for the plain text 
                email body.
            context: A context dictionary to use when rendering the password reset 
                email templates.
            from_email: The From email address.
            to_email: The To email address.
            html_email_template_name: Optional; Path of the template to use for 
                the HTML email body. Defaults to None.
        """
        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=from_email, to=[to_email],
                                               reply_to=[from_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.mixed_subtype = "related"
            mime_image = get_as_mime_image(image_file_path=LOGO_FILE_PATH, cid_name=LOGO_CID_NAME)
            email_message.attach(mime_image)  # type: ignore

        email_message.send()
 

5. Установите django.contrib.auth.views.PasswordResetView.form_class для использования ваш новый PasswordResetForm подкласс.

Django urls.py файл

 from django.contrib.auth import views

from your_app.forms import CustomPasswordResetForm


views.PasswordResetView.form_class = CustomPasswordResetForm

urlpatterns = [
    path('', home_view, name='home'),
    path('accounts/', include('django.contrib.auth.urls')),
    ...
]
 

Завершить forms.py

 """Module that overrides the default Django password reset functionality by 
sending emails containing both plain text as well as HTML along with the company logo.
"""

from email.mime.image import MIMEImage
from typing import Dict, Final, Optional

from django.contrib.auth import get_user_model
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.tokens import default_token_generator, PasswordResetTokenGenerator
from django.contrib.sites.shortcuts import get_current_site
from django.contrib.staticfiles import finders
from django.core.handlers.wsgi import WSGIRequest
from django.core.mail import EmailMultiAlternatives
from django.template import loader
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode


# Constants for sending password-reset emails.
LOGO_FILE_PATH: Final[str] = "img/logo.png"
LOGO_CID_NAME: Final[str] = "logo"
PASSWORD_RESET_FORM_TEMPLATE: Final[str] = "registration/password_reset_form.html"
PASSWORD_RESET_HTML_TEMPLATE: Final[str] = "registration/password_reset_email.html"
PASSWORD_RESET_TEXT_TEMPLATE: Final[str] = "registration/password_reset_email.txt"
PASSWORD_RESET_SUBJECT_TEMPLATE: Final[str] = "registration/password_reset_subject.txt"
SUPPORT_EMAIL: Final[str] = "YOUR_SUPPORT_EMAIL_ADDRESS"
FROM_EMAIL: Final[str] = f"YOUR_COMPANY_NAME Support <{SUPPORT_EMAIL}>"


def get_as_mime_image(image_file_path: str, cid_name: str) -> MIMEImage:
    """Fetch an image file and return it wrapped in a ``MIMEImage`` object for use 
    in emails.

    After the ``MIMEImage`` has been attached to an email, reference the image in 
    the HTML using the Content ID.

    Example:

    If the CID name is "logo", then the HTML reference would be:

    <img src="cid:logo" />

    Args:
        image_file_path: The path of the image. The path must be findable by the 
            Django staticfiles app.
        cid_name: The Content-ID name to use within the HTML email body to 
            reference the image.

    Raises:
        FileNotFoundError: If the image file cannot be found by the staticfiles app.

    Returns:
        MIMEImage: The image wrapped in a ``MIMEImage`` object and the Content ID 
        set to ``cid_name``.
    """
    paths = finders.find(image_file_path)
    if paths is None:
        raise FileNotFoundError(f"{image_file_path} not found in static files")

    if isinstance(paths, list):
        final_path = paths[0]
    else:
        final_path = paths
    with open(final_path, 'rb') as f:
        image_data = f.read()

    mime_image = MIMEImage(image_data)
    mime_image.add_header("Content-ID", f"<{cid_name}>")
    return mime_image


class CustomPasswordResetForm(PasswordResetForm):
    """Override the default Django password-reset form to send the password reset email using both HTML and plain text.
    """
    def send_mail(
        self,
        subject_template_name: str,
        email_template_name: str,
        context: Dict[str, str],
        from_email: Optional[str],
        to_email: str,
        html_email_template_name: Optional[str] = None,
    ) -> None:
        """Send a ``django.core.mail.EmailMultiAlternatives`` to ``to_email``.

        This method also attaches the company logo, which can be added to the 
        email HTML template using:

        <img src="cid:logo" />

        Args:
            subject_template_name: Path of the template to use as the email 
                subject.
            email_template_name: Path of the template to use for the plain text 
                email body.
            context: A context dictionary to use when rendering the password reset 
                email templates.
            from_email: The From email address.
            to_email: The To email address.
            html_email_template_name: Optional; Path of the template to use for 
                the HTML email body. Defaults to None.
        """
        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=from_email, to=[to_email],
                                               reply_to=[from_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.mixed_subtype = "related"
            mime_image = get_as_mime_image(image_file_path=LOGO_FILE_PATH, cid_name=LOGO_CID_NAME)
            email_message.attach(mime_image)  # type: ignore

        email_message.send()

    def save(
        self,
        domain_override: Optional[str] = None,
        subject_template_name: str = PASSWORD_RESET_SUBJECT_TEMPLATE,
        email_template_name: str = PASSWORD_RESET_TEXT_TEMPLATE,
        use_https: Optional[bool] = None,
        token_generator: PasswordResetTokenGenerator = default_token_generator,
        from_email: Optional[str] = FROM_EMAIL,
        request: Optional[WSGIRequest] = None,
        html_email_template_name: Optional[str] = PASSWORD_RESET_HTML_TEMPLATE,
        extra_email_context: Optional[Dict[str, str]] = None
    ) -> None:
        """Generate a one-use only link for resetting password and email it to 
        the user.

        Args:
            domain_override: Optional; Domain name to use in the email message 
                template that overrides the actual domain from which the email is 
                sent. Defaults to None.
            subject_template_name: Optional; Warning: this argument is overridden 
                by the global variable ``PASSWORD_RESET_SUBJECT_TEMPLATE``.
            email_template_name: Optional; Warning: this argument is overridden by 
                the global variable ``PASSWORD_RESET_TEXT_TEMPLATE``.
            use_https: Optional; If True, use HTTPS, otherwise use HTTP. Defaults 
                to False. Note that if the password reset HTTP request is received 
                via HTTPS, `use_https` will be set to True by the auth view.
            token_generator: Optional; Strategy object used to generate and check 
                tokens for the password reset mechanism. Defaults to an instance 
                of ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
            from_email: Optional; Warning: this argument is overridden by the 
                global variable``FROM_EMAIL``.
            request: Optional; The HttpRequest object. Defaults to None.
            html_email_template_name: Warning: this argument is overridden by the 
                global variable ``PASSWORD_RESET_HTML_TEMPLATE``.
            extra_email_context: Optional; Key-value pairs to add to the context 
                dictionary used to render the password reset email templates. 
                    Defaults to None.
        """
        email_template_name = PASSWORD_RESET_TEXT_TEMPLATE
        from_email = FROM_EMAIL
        html_email_template_name = PASSWORD_RESET_HTML_TEMPLATE
        subject_template_name = PASSWORD_RESET_SUBJECT_TEMPLATE

        email = self.cleaned_data["email"]
        if not domain_override:
            current_site = get_current_site(request)
            site_name = current_site.name
            domain = current_site.domain
        else:
            site_name = domain = domain_override
        UserModel = get_user_model()
        email_field_name = UserModel.get_email_field_name()  # type: ignore

        for user in self.get_users(email):
            user_email = getattr(user, email_field_name)
            context = {
                'email': user_email,
                'domain': domain,
                'site_name': site_name,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': 'https' if use_https else 'http',
                **(extra_email_context or {}),
            }

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

Ответ №4:

Вы можете использовать PasswordResetSerializer http://django-rest-auth.readthedocs.io/en/latest/configuration.html

Затем вы можете переопределить все параметры формы:

domain_override subject_template_name email_template_name use_https token_generator from_email запрос html_email_template_name extra_email_context

в моем случае я просто переопределяю 2 реквизита

 class CustomPasswordResetSerializer(PasswordResetSerializer):

    def get_email_options(self):
        return {
            'domain_override': 'anydomain.com',
            'html_email_template_name': 'your_temp/password_reset_email.html',
        }
 

Ответ №5:

Вот простой подход, который сработал для меня. Добавление нашего пользовательского пути к шаблону таким образом сработало для меня.

path('users/password/reset/', password_reset, {'html_email_template_name': 'registration/password_reset_email.html'},name='password_reset'),

Ответ №6:

После некоторого количества проб и ошибок я обнаружил гораздо более краткий способ отправки пользовательского шаблонного электронного письма для сброса пароля в последней версии Django (1.8).

В вашем project/urls.py добавьте эти импорта:

 from django.contrib.auth import views as auth_views
from django.core.urlresolvers import reverse_lazy
 

И добавьте следующий маршрут в свои urlpatterns перед обычным включением в маршрут django contrib auth url:

 url(r'^accounts/password/reset/

А затем в  templates/registration  папке вашего приложения создайте  password_reset_html_email.html  любой HTML-шаблон, который вы хотите.

Причина, по которой это казалось необходимым, заключалась в источнике, для  django/contrib/auth/views.py  которого есть функция просмотра, к которой сопоставлен исходный маршрут URL:

 147 def password_reset(request, is_admin_site=False,
148                    template_name='registration/password_reset_form.html',
149                    email_template_name='registration/password_reset_email.html',
150                    subject_template_name='registration/password_reset_subject.txt',
151                    password_reset_form=PasswordResetForm,
152                    token_generator=default_token_generator,
153                    post_reset_redirect=None,
154                    from_email=None,
155                    current_app=None,
156                    extra_context=None,
157                    html_email_template_name=None):
158
 

Значение html_email_template_name установлено None по умолчанию, и, похоже, не было способа присвоить его значение, кроме перезаписи этого конкретного маршрута для этого случая, как я упоминал выше.

Надеюсь, это поможет без необходимости копировать-вставлять кучу почти идентичного кода, как некоторые другие предложенные ответы - обратная связь приветствуется, конечно!

Ответ №7:

Для меня исследование было трудоемким, но решение довольно тривиальным. Никаких переопределений, никаких манипуляций с формами или что-то в этом роде, я использую Django == 1.8.6, но должен работать как минимум с django 1.7 и далее. Чтобы включить поддержку электронных писем в формате html в password_reset, все, что мне нужно было сделать, это изменить имя ключа шаблона электронной почты в функции сброса с email_template_name='emails/password_reset_email_html.html

Для

html_email_template_name='emails/password_reset_email_html.html ',

таким образом, функция сброса будет выглядеть так:

 def reset(request):
# Wrap the built-in password reset view and pass it the arguments
# like the template name, email template name, subject template name
# and the url to redirect after the password reset is initiated.
return password_reset(request, template_name='profile/reset.html',
    html_email_template_name='emails/password_reset_email_html.html',
    subject_template_name='emails/reset_subject.txt',
    post_reset_redirect=reverse('success'))
 

Комментарии:

1. Где подходящее место в структуре проекта django для этого?

Ответ №8:

Основываясь на решении Джема Козиноглу, я бы предложил изменить форму и перегрузить send_mail вместо метода сохранения следующим образом:

 class CustomPasswordResetForm(PasswordResetForm):

    def send_mail(self, subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name=None):
        """
            Sends 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])
        # New line introduce
        email_message.attach_alternative(body, 'text/html')

        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()
 

Ответ №9:

После перезаписи PasswordResetForm и добавления этой строки кода после инициализации email_message я решаю свою проблему:

 email_message.attach_alternative(body, 'text/html')
 

,
'YOUR_APP.views.password_reset',
{'post_reset_redirect' : '/#/login?resetemail=true'},
name="password_reset"),
views.py


form.py


Комментарии:

1. Я получаю эту ошибку: ошибка атрибута в объекте /user/password/reset/ 'CustomPasswordResetForm' не имеет атрибута 'users_cache'. Вы допустили ошибку? Должен ли я использовать какую-либо другую функцию вместо users_cache()? Что делают другие.

Ответ №2:

Вы можете переопределить save метод django.contrib.auth.forms.PasswordResetForm и передать новую форму в качестве аргумента для password_reset просмотра.

Ответ №3:

Электронное письмо с сбросом пароля HTML с изображениями в Django 3.0

Обзор

  1. Создайте три шаблона:
    • password_reset_email.html
    • password_reset_email.txt
    • password_reset_subject.txt
  2. Переопределение django.contrib.auth.forms.PasswordResetForm путем создания подкласса.
  3. Переопределите аргументы для PasswordResetForm.save() , чтобы указать на ваши пользовательские шаблоны.
  4. Переопределите PasswordResetForm.send_email() , если вы хотите вставлять изображения в HTML-сообщение электронной почты.
  5. Установите django.contrib.auth.views.PasswordResetView.form_class для использования ваш новый PasswordResetForm подкласс.

1. Создайте три шаблона

  • В вашем каталоге шаблонов Django создайте подкаталог с именем "регистрация".
  • В разделе "шаблоны / регистрация" добавьте три шаблона:
    • password_reset_email.html
    • password_reset_email.txt
    • password_reset_subject.txt
  • Шаблон электронной почты HTML должен быть хорошо структурированным HTML-документом. Смотрите пример ниже.
  • Шаблон "* .txt" должен быть простым шаблоном (без HTML). Смотрите пример ниже.

Пример password_reset_email.html


Пример password_reset_email.txt


2. Override django.contrib.auth.forms.PasswordResetForm

  • In your Django app directory, create a module named "forms.py".
  • Create a subclass of django.contrib.auth.forms.PasswordResetForm and override the save() method.

Example: forms.py


3. Override the arguments for PasswordResetForm.save() to point to your custom templates.

  • In your "forms.py" module, add global variables as follows:

Example forms.py


4. Override PasswordResetForm.send_email() if you want to embed images in the HTML email.

Example: forms.py


5. Установите django.contrib.auth.views.PasswordResetView.form_class для использования ваш новый PasswordResetForm подкласс.

Django urls.py файл


Завершить forms.py


Ответ №4:

Вы можете использовать PasswordResetSerializer http://django-rest-auth.readthedocs.io/en/latest/configuration.html

Затем вы можете переопределить все параметры формы:

domain_override subject_template_name email_template_name use_https token_generator from_email запрос html_email_template_name extra_email_context

в моем случае я просто переопределяю 2 реквизита


Ответ №5:

Вот простой подход, который сработал для меня. Добавление нашего пользовательского пути к шаблону таким образом сработало для меня.

path('users/password/reset/', password_reset, {'html_email_template_name': 'registration/password_reset_email.html'},name='password_reset'),

Ответ №6:

После некоторого количества проб и ошибок я обнаружил гораздо более краткий способ отправки пользовательского шаблонного электронного письма для сброса пароля в последней версии Django (1.8).

В вашем project/urls.py добавьте эти импорта:


И добавьте следующий маршрут в свои urlpatterns перед обычным включением в маршрут django contrib auth url:


А затем в templates/registration папке вашего приложения создайте password_reset_html_email.html любой HTML-шаблон, который вы хотите.

Причина, по которой это казалось необходимым, заключалась в источнике, для django/contrib/auth/views.py которого есть функция просмотра, к которой сопоставлен исходный маршрут URL:


Значение html_email_template_name установлено None по умолчанию, и, похоже, не было способа присвоить его значение, кроме перезаписи этого конкретного маршрута для этого случая, как я упоминал выше.

Надеюсь, это поможет без необходимости копировать-вставлять кучу почти идентичного кода, как некоторые другие предложенные ответы - обратная связь приветствуется, конечно!

Ответ №7:

Для меня исследование было трудоемким, но решение довольно тривиальным. Никаких переопределений, никаких манипуляций с формами или что-то в этом роде, я использую Django == 1.8.6, но должен работать как минимум с django 1.7 и далее. Чтобы включить поддержку электронных писем в формате html в password_reset, все, что мне нужно было сделать, это изменить имя ключа шаблона электронной почты в функции сброса с email_template_name='emails/password_reset_email_html.html

Для

html_email_template_name='emails/password_reset_email_html.html ',

таким образом, функция сброса будет выглядеть так:


Комментарии:

1. Где подходящее место в структуре проекта django для этого?

Ответ №8:

Основываясь на решении Джема Козиноглу, я бы предложил изменить форму и перегрузить send_mail вместо метода сохранения следующим образом:


Ответ №9:

После перезаписи PasswordResetForm и добавления этой строки кода после инициализации email_message я решаю свою проблему:


,
auth_views.password_reset,
{
'post_reset_redirect': reverse_lazy('auth_password_reset_done'),
'html_email_template_name': 'registration/password_reset_html_email.html'
},
name='auth_password_reset'),

url('^', include('django.contrib.auth.urls')),
А затем в templates/registration папке вашего приложения создайте password_reset_html_email.html любой HTML-шаблон, который вы хотите.

Причина, по которой это казалось необходимым, заключалась в источнике, для django/contrib/auth/views.py которого есть функция просмотра, к которой сопоставлен исходный маршрут URL:


Значение html_email_template_name установлено None по умолчанию, и, похоже, не было способа присвоить его значение, кроме перезаписи этого конкретного маршрута для этого случая, как я упоминал выше.

Надеюсь, это поможет без необходимости копировать-вставлять кучу почти идентичного кода, как некоторые другие предложенные ответы — обратная связь приветствуется, конечно!

Ответ №7:

Для меня исследование было трудоемким, но решение довольно тривиальным. Никаких переопределений, никаких манипуляций с формами или что-то в этом роде, я использую Django == 1.8.6, но должен работать как минимум с django 1.7 и далее. Чтобы включить поддержку электронных писем в формате html в password_reset, все, что мне нужно было сделать, это изменить имя ключа шаблона электронной почты в функции сброса с email_template_name=’emails/password_reset_email_html.html

Для

html_email_template_name=’emails/password_reset_email_html.html ‘,

таким образом, функция сброса будет выглядеть так:


Комментарии:

1. Где подходящее место в структуре проекта django для этого?

Ответ №8:

Основываясь на решении Джема Козиноглу, я бы предложил изменить форму и перегрузить send_mail вместо метода сохранения следующим образом:


Ответ №9:

После перезаписи PasswordResetForm и добавления этой строки кода после инициализации email_message я решаю свою проблему:


,
‘YOUR_APP.views.password_reset’,
{‘post_reset_redirect’ : ‘/#/login?resetemail=true’},
name=«password_reset»),views.py


form.py


Комментарии:

1. Я получаю эту ошибку: ошибка атрибута в объекте /user/password/reset/ ‘CustomPasswordResetForm’ не имеет атрибута ‘users_cache’. Вы допустили ошибку? Должен ли я использовать какую-либо другую функцию вместо users_cache()? Что делают другие.

Ответ №2:

Вы можете переопределить save метод django.contrib.auth.forms.PasswordResetForm и передать новую форму в качестве аргумента для password_reset просмотра.

Ответ №3:

Электронное письмо с сбросом пароля HTML с изображениями в Django 3.0

Обзор

  1. Создайте три шаблона:
    • password_reset_email.html
    • password_reset_email.txt
    • password_reset_subject.txt
  2. Переопределение django.contrib.auth.forms.PasswordResetForm путем создания подкласса.
  3. Переопределите аргументы для PasswordResetForm.save() , чтобы указать на ваши пользовательские шаблоны.
  4. Переопределите PasswordResetForm.send_email() , если вы хотите вставлять изображения в HTML-сообщение электронной почты.
  5. Установите django.contrib.auth.views.PasswordResetView.form_class для использования ваш новый PasswordResetForm подкласс.

1. Создайте три шаблона

  • В вашем каталоге шаблонов Django создайте подкаталог с именем «регистрация».
  • В разделе «шаблоны / регистрация» добавьте три шаблона:
    • password_reset_email.html
    • password_reset_email.txt
    • password_reset_subject.txt
  • Шаблон электронной почты HTML должен быть хорошо структурированным HTML-документом. Смотрите пример ниже.
  • Шаблон «* .txt» должен быть простым шаблоном (без HTML). Смотрите пример ниже.

Пример password_reset_email.html


Пример password_reset_email.txt


2. Override django.contrib.auth.forms.PasswordResetForm

  • In your Django app directory, create a module named «forms.py».
  • Create a subclass of django.contrib.auth.forms.PasswordResetForm and override the save() method.

Example: forms.py


3. Override the arguments for PasswordResetForm.save() to point to your custom templates.

  • In your «forms.py» module, add global variables as follows:

Example forms.py


4. Override PasswordResetForm.send_email() if you want to embed images in the HTML email.

Example: forms.py


5. Установите django.contrib.auth.views.PasswordResetView.form_class для использования ваш новый PasswordResetForm подкласс.

Django urls.py файл


Завершить forms.py


Ответ №4:

Вы можете использовать PasswordResetSerializer http://django-rest-auth.readthedocs.io/en/latest/configuration.html

Затем вы можете переопределить все параметры формы:

domain_override subject_template_name email_template_name use_https token_generator from_email запрос html_email_template_name extra_email_context

в моем случае я просто переопределяю 2 реквизита


Ответ №5:

Вот простой подход, который сработал для меня. Добавление нашего пользовательского пути к шаблону таким образом сработало для меня.

path('users/password/reset/', password_reset, {'html_email_template_name': 'registration/password_reset_email.html'},name='password_reset'),

Ответ №6:

После некоторого количества проб и ошибок я обнаружил гораздо более краткий способ отправки пользовательского шаблонного электронного письма для сброса пароля в последней версии Django (1.8).

В вашем project/urls.py добавьте эти импорта:


И добавьте следующий маршрут в свои urlpatterns перед обычным включением в маршрут django contrib auth url:


А затем в templates/registration папке вашего приложения создайте password_reset_html_email.html любой HTML-шаблон, который вы хотите.

Причина, по которой это казалось необходимым, заключалась в источнике, для django/contrib/auth/views.py которого есть функция просмотра, к которой сопоставлен исходный маршрут URL:


Значение html_email_template_name установлено None по умолчанию, и, похоже, не было способа присвоить его значение, кроме перезаписи этого конкретного маршрута для этого случая, как я упоминал выше.

Надеюсь, это поможет без необходимости копировать-вставлять кучу почти идентичного кода, как некоторые другие предложенные ответы — обратная связь приветствуется, конечно!

Ответ №7:

Для меня исследование было трудоемким, но решение довольно тривиальным. Никаких переопределений, никаких манипуляций с формами или что-то в этом роде, я использую Django == 1.8.6, но должен работать как минимум с django 1.7 и далее. Чтобы включить поддержку электронных писем в формате html в password_reset, все, что мне нужно было сделать, это изменить имя ключа шаблона электронной почты в функции сброса с email_template_name=’emails/password_reset_email_html.html

Для

html_email_template_name=’emails/password_reset_email_html.html ‘,

таким образом, функция сброса будет выглядеть так:


Комментарии:

1. Где подходящее место в структуре проекта django для этого?

Ответ №8:

Основываясь на решении Джема Козиноглу, я бы предложил изменить форму и перегрузить send_mail вместо метода сохранения следующим образом:


Ответ №9:

После перезаписи PasswordResetForm и добавления этой строки кода после инициализации email_message я решаю свою проблему: