django搭建博客九用户密码重置

2022年05月28日 未雨晴空 4评论 86阅读 3喜欢

页面模板

新建\myblog\templates\user\register.html

{% extends 'base.html' %}
{% load static %}
{% block title %}密码重置{% endblock %}
{% block main %}
    <!--主内容-start--->
    <div class="container">
        <form class="form-signin bg-white" method="post" action="{% url 'sys:reset_password' %}">
            <div class="text-center mb-4">
                <img class="mb-2" src="{% static 'images/favicon.png' %}" alt="" width="100" height="100">
                <h1 class="h3 mb-3 font-weight-normal">密码重置</h1>
                <div class="rollContainer">
                    <p class="rollBlock">请按照密码格式要求重新设置你的密码。</p>
                </div>
                <div class="login_error">
                    {% for k,v in reset_form.errors.items %}
                        {{ v }}
                    {% endfor %}
                </div>
            </div>
            <div class="form-label-group">
                <input type="password" id="inputPassword" name="password"
                       value="{% if reset.password.value %}{{ reset_form.password.value }}{% endif %}"
                       class="form-control {% if reset_form.errors.password %}is-invalid{% endif %}" placeholder="新密码"
                       aria-describedby="passwordHelpBlock" required autofocus>
                <label for="inputPassword">新密码</label>
                <small id="passwordHelpBlock" class="form-text text-muted">
                    密码必须以字母开头,长度在5~18之间,只能包括字母,数字以及.@+-_?&%$这些字符
                </small>
            </div>
            <input type="hidden" name="email"
                   value="{% if reset_form.email.value %}{{ reset_form.email.value }}{% else %}{{ email }}{% endif %}">
            <button class="btn btn-lg btn-success btn-block" type="submit">重置密码</button>
            {% csrf_token %}
        </form>
        <div class="clearfix " style="width: 100%;max-width: 420px;padding: 15px;margin: auto;">
            <p class="float-left"><a class="text-muted " href="/">←回到首页</a></p>
            <p class="float-right">
                <a class="text-muted " href="{% url 'sys:login' %}">登录</a>
                |
                <a class="text-muted " href="{% url 'sys:register' %}">注册</a>
            </p>
        </div>
    </div>

{% endblock %}

页面效果:

在这里插入图片描述

密码重置邮件

编辑\myblog\system\tools.py

内容如下,RegisterActiveEmailSender继承之前封装的EmailSender,重写了get_template_context函数,实现了注册激活需要的参数逻辑。

from django.urls import reverse
from django.utils.crypto import get_random_string
from system.models import EmailRecord, User
from django.core.mail import send_mail
from django.template.loader import render_to_string
from myblog.email_settings import EMAIL_FROM
from myblog.settings import SITE_URL, SITE_NAME
import logging

logger = logging.getLogger(__name__)

...

"""
密码重置邮件发送器
"""

class PasswordResetEmailSender(EmailSender):
    template_name = "user/email-password-reset.html"

    def get_template_context(self):
        context = super(PasswordResetEmailSender, self).get_template_context()
        self.record.url = self.site_url + reverse(viewname='sys:reset_password') + f"?code={self.record.code}"
        context.update({"url": self.record.url})
        return context

密码重置邮件任务

新增\myblog\system\tasks.py

添加以下内容,需要注意这里文件名必须为tasks.py,便于后面celery的自动任务发现机制。可以看到下面发送邮件是区分了两种环境的。

如果是DEBUG=False(生产环境)的情况下则是交给celery异步发送邮件,同时在之前prod_settings.py里面已经配置过 EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"

而在DEBUG=True(开发环境)则是同步发送且因为在dev_settings.py里面定义了

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" ,邮件直接输出在控制台,便于开发调试。

from celery import shared_task
from django.conf import settings
from system.models import EmailType
from system.tools import RegisterActiveEmailSender, PasswordResetEmailSender
import logging

logger = logging.getLogger("django")


@shared_task
def _send_email(email_type=None, username=None, *args, **kwargs):
    if email_type == EmailType.ACTIVE:
        RegisterActiveEmailSender(EmailType.ACTIVE, username).send(*args, **kwargs)
    elif email_type == EmailType.RESET:
        PasswordResetEmailSender(EmailType.RESET, username).send(*args, **kwargs)


def send_email(email_type=None, username=None, *args, **kwargs):
    if settings.DEBUG:
        _send_email(email_type, username, *args, **kwargs)
    else:
        _send_email.delay(email_type, username, *args, **kwargs)

密码重置表单

编写\myblog\system\forms.py

添加以下内容,需要注意这里面使用到了django-simple-captcha依赖,如下面的

from captcha.fields import CaptchaField,这个在之前初始化工程的时候已经安装了开发环境下需要的依赖了。

from django import forms
from django.core import validators

from system.models import User
import logging

logger = logging.getLogger('django')


class ResetPasswordForm(forms.Form):
    email = forms.EmailField(required=True, max_length=30, error_messages={'require': "请输入邮箱地址"})
    password = forms.CharField(required=True, error_messages={'require': "请输入密码"}, min_length=5, max_length=18,
                               validators=[
                                   validators.RegexValidator(regex=r'[\w.@+-_?&%$)!]{6,18}$',
                                                             message="请输入合法的密码")])

    def clean_email(self):
        email = self.cleaned_data.get('email')
        if email is not None:
            exists = User.objects.filter(email=email).exists()  # 之所以用filter是因为如果用get若不存在则会报错
            if not exists:
                logger.info("【{email}】邮箱不存在!".format(email=email))
                raise forms.ValidationError("邮箱不存在!")
        return email

密码重置视图

编写\myblog\system\views.py

添加以下内容

import logging

from django.shortcuts import render, redirect
from django.urls import reverse
from django.views.generic.base import View

from system import forms
from system.models import EmailRecord, User

logger = logging.getLogger('django')

class ResetPasswordView(View):

    def get(self, request):
        code = request.GET.get("code", None)
        try:
            record = EmailRecord.objects.get(code=code)
            return render(request, "user/reset.html", {"email": record.receiver.email})
        except EmailRecord.DoesNotExist:
            logger.info("【{code}】激活验证码不存在!".format(code=code))
            return redirect("/")

    def post(self, request):
        reset_form = forms.ResetPasswordForm(request.POST)
        if reset_form.is_valid():
            email = reset_form.cleaned_data['email']
            password = reset_form.cleaned_data['password']
            user = User.objects.get(email=email)
            user.set_password(password)
            user.save()
            return redirect(reverse("sys:login"))
        return render(request, 'user/reset.html', {'reset_form': reset_form})

路由绑定

编辑\myblog\system\urls.py

添加以下内容

from django.urls import path
from system import views

urlpatterns = [
    path('user/reset_password', views.ResetPasswordView.as_view(), name='reset_password'),
]
  1. LPL
    2022-06-22 13:06:41

    大佬,教程写完了?才九篇,太少了

    回复
    1. 2022-06-22 13:06:51

      本来是准备直接肝完,后面我看文章没多少访问量就没继续码了

      回复
      1. LPL admin
        2022-06-22 14:06:53

        博客文章少,搜索引擎收录少,所以看的人少,赶紧码起来

        回复
        1. 2022-06-22 14:06:39

          行,知道有人看的话,那我继续码!

          回复

发表评论 取消回复

电子邮件地址不会被公开。

请输入以http或https开头的URL,格式如:https://oneisall.top