Как программно вызвать электронную почту для сброса пароля в django 1.7.6?

Я столкнулся с проблемой, когда мне пришлось загрузить более 200 новых пользователей в мое приложение django и сразу же отправить им письмо для сброса пароля. Это должно было произойти только один раз, сделано только мной и тихо работать на сервере. Работа в Интернете привела меня только к одному более или менее правильному ответу: триггер электронной почты для сброса пароля в django без браузера?, Единственной проблемой было то, что этому посту было около 4 лет, и, конечно, когда я попробовал решение, оно не сработало...

3 ответа

Решение

Два наиболее ценных пункта из упомянутой мной ссылки:
1) В более поздней версии Django нам нужно вызвать form.is_valid ()
2) Отправка электронной почты осуществляется после сохранения ().

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

    def find_users_and_send_email():
       from django.http import HttpRequest
       from django.contrib.auth.forms import PasswordResetForm
       from django.contrib.auth.models import User

       users = User.objects.filter(date_joined__gt = '2015-04-16')
       for user in users:
       try:

        if user.email:
            log.info("Sending email for to this email:", user.email)
            form = PasswordResetForm({'email': user.email})

            assert form.is_valid()
            request = HttpRequest()
            request.META['SERVER_NAME'] = 'help.mydomain.com'
            request.META['SERVER_PORT'] = '443'
            form.save(
                request= request,
                use_https=True,
                from_email="username@gmail.com", 
                    email_template_name='registration/password_reset_email.html')

       except Exception as e:
          log.info(e)
          continue

return 'done'

1) Обычно PasswordResetForm работает с "запросом" от внешнего интерфейса, которого у меня не было. Так что я просто создал один.
2) Когда я последовал примеру в ссылке, это не удалось.. Не удалось найти имя сервера в запросе. (Имеет смысл, потому что я создал свой запрос из ниоткуда)
3) Когда я исправил имя сервера, он спросил порт сервера. Так как я использовал https, мой порт 443, в противном случае используйте порт по умолчанию. 4) Если вы используете https, не забудьте указать его при сохранении формы (use_https = True)

Я счел полезным заключить ответ @chabislav в специальную команду управления, которую затем можно будет повторно использовать при необходимости. Обратите внимание, что я удалил фильтр объектов пользователя, так как знал, что хочу отправить инструкции по сбросу пароля всем пользователям.

# myproject/myapp/management/commands/send_password_reset_emails.py
from django.core.management.base import BaseCommand, CommandError
# I use a custom user model, so importing that rather than the standard django.contrib.auth.models
from users.models import User
from django.http import HttpRequest
from django.contrib.auth.forms import PasswordResetForm


class Command(BaseCommand):
    help = 'Emails password reset instructions to all users'

    def handle(self, *args, **kwargs):
        users = User.objects.all()
        for user in users:
            try:
                if user.email:
                    print("Sending email for to this email:", user.email)
                    form = PasswordResetForm({'email': user.email})
                    assert form.is_valid()
                    request = HttpRequest()
                    request.META['SERVER_NAME'] = 'www.example.com'
                    request.META['SERVER_PORT'] = 443
                    form.save(
                        request= request,
                        use_https=True,
                        from_email="admin@mysite.com", 
                        email_template_name='registration/password_reset_email.html'
                        )
            except Exception as e:
                print(e)
                continue

        return 'done'

Затем это можно легко запустить с помощью python manage.py send_password_reset_emails.

Обратите внимание, что я получил сообщение об ошибке (550, b'5.7.1 Relaying denied'), что в конечном итоге стало проблемой, связанной с настройкой моего почтового сервера localhost, но как только это было очищено, это работало довольно хорошо. Наличие этого параметра в команде управления также хорошо, потому что оно не засоряет код, который вы регулярно используете (представления).

Если вы читаете это с django 3.x или 4.x И используете django-allauth, это сработает для вас:

      from allauth.account.forms import ResetPasswordForm # note the different form import

form = ResetPasswordForm({"email": "some@mail.io"})

assert form.is_valid() # required because we need clean() executed
form.save(
    request=None,
    from_email="noreply@example.io",
)

Обратите внимание, что это будет принимать все значения из конфигурации allauth , используяdjango.contrib.sites.

Другие вопросы по тегам