【问题标题】:How to programmatically trigger password reset email in django 1.7.6?如何在 django 1.7.6 中以编程方式触发密码重置电子邮件?
【发布时间】:2015-07-16 03:02:47
【问题描述】:

我遇到了一个问题,我必须将 200 多个新用户加载到我的 django 应用程序中,并立即向他们发送密码重置电子邮件。这必须只发生一次,只由我完成并在后端安静地运行。上网冲浪只给了我一个或多或少的正确答案:Trigger password reset email in django without browser?。唯一的问题是这篇文章已经有 4 年的历史了,当然,当我尝试解决方案时,它没有用......

【问题讨论】:

    标签: python django passwords reset programmatically-created


    【解决方案1】:

    我提到的链接中最有价值的两点:

    1. 在最新版本的 Django 中,我们需要调用form.is_valid()
    2. 通过save() 发送电子邮件。

    以下是我查询我需要的用户并向他们每个人发送密码重置链接的方式:

    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
        import logging
        logger = logging.getLogger(__name__)
        
        users = User.objects.filter(date_joined__gt = '2015-04-16')
        for user in users:
            try:
                if user.email:
                    logger.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:
                logger.warning(str(e))
                continue
    
        return 'done'
    
    1. 通常PasswordResetForm 处理来自前端的“请求”,而我没有。所以我简单地创建了一个。
    2. 当我按照链接中的示例进行操作时,它失败了。它在请求中找不到服务器名称。 (有道理,因为我突然实例化了我的请求)
    3. 当我固定服务器名称时,它要求提供服务器端口。由于我使用的是https,所以我的端口是443,否则使用默认端口。
    4. 如果您使用https,请不要忘记在保存表单时注明use_https=True

    【讨论】:

    • 除了创建请求之外,您还可以将form.save() 中的domain_override 设置为您希望在重置电子邮件中显示为您的域的任何内容(这将用于链接和用于电子邮件的默认主题)
    【解决方案2】:

    我发现将@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'),这最终导致我的本地主机电子邮件服务器的设置方式出现问题,但一旦清除,它就运行良好。将它放在管理命令中也很好,因为它不会阻塞您定期使用的代码(视图)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-01
      • 2021-08-05
      • 2018-10-07
      • 2020-02-15
      • 2020-09-26
      • 2013-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多