Django项目于之在线教育平台网站的实战开发(二)

说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!

接着上一篇博客继续往下写 :https://blog.youkuaiyun.com/qq_41782425/article/details/89788542

非VIP用户请点击这里进行查阅

目录

一丶用户登录注册功能实现

二丶找回密码(忘记密码)


一丶用户登录注册功能实现

1.渲染网站主页面

  • 在项目根目录下创建static目录,将资源文件拷贝到目录中

  • 将static/html目录中的主页模板index.html文件拷贝到templates模板目录中,并修改代码中引入的静态资源路径,例如下

  • 在settings目录中添加static静态资源目录
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
  • 在根级urls中定义主页路由
url(r'^$', TemplateView.as_view(template_name="index.html"), name="index")

2.渲染登录页以及注册页

  • 跟主页一样首先拷贝login.html和register.html模板文件到templates目录中,修改静态资源路径(不演示),在根级urls中配置登录页和注册页的路由规则
urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^xadmin/', xadmin.site.urls),
    url(r'^$', TemplateView.as_view(template_name="index.html"), name="index"),
    url(r'^login/$', TemplateView.as_view(template_name="login.html"), name="login"),
    url(r'^register/$', TemplateView.as_view(template_name="register.html"), name="register")
]
  • 在主页丶登录页以及注册页中将所有涉及到的注册登录链接地址修改如下
<a style="color:white" class="fr registerbtn" href="/register/">注册</a>
<a style="color:white" class="fr loginbtn" href="/login/">登录</a>
  • 测试注册登录页面间跳转与显示

3.实现登录功能

  • 在users/views中定义登录视图函数,视图函数逻辑为首先根据用户请求方式进行不同的逻辑处理,登录逻辑代码简单,需要注意的是,用户进行登录时需要提交表单post请求,获取请求携带参数username和password,django提供了authenticate方法,向数据库对应表发起验证,判断用户填写的用户名和密码是否正确,正确返回对象,不正确返回None;同时提供了login方法,该方法才是完成正常的登录
from django.shortcuts import render
from django.contrib.auth import authenticate, login
# Create your views here.


def user_login(request):
    if request.method == "GET":
        return render(request, "login.html")
    elif request.method == "POST":
        user_name = request.POST.get("username", "")
        pass_word = request.POST.get("password", "")
        user = authenticate(username=user_name, password=pass_word)
        if user is not None:
            login(request, user)
            return render(request, "index.html")
        else:
            return render(request, "login.html")
  • 对应的login.html登录模板中修改form表单请求地址,以及请求方式并且定义csrf
 <form action="/login/" method="post" autocomplete="off">
  • 在根级urls中,当比配login/ 路由时需要去调用定义的user_login视图函数,而不是渲染模板文件,所以需要进行如下修改
url(r'^login/$', user_login, name="login"),
  • 当登录成功后,即在index主页面不应该显示登录与注册按钮,而是显示出登录成功后的用户信息,所以在主页模板文件中需要进行如下判断,这里需要使用django默认传递的request参数到模板中去掉用user对象中的is_authenticated方法判断用户是否登录成功,说明一点这里还未替换登录成功后显示的用户信息,只是作于判断显示用户信息模块还是登录注册模块
{% if request.user.is_authenticated %}
<div class="personal">
    <dl class="user fr">
        <dd>bobby<img class="down fr" src="{% static 'images/top_down.png' %}"/></dd>
        <dt><img width="20" height="20" src="{% static 'media/image/2016/12/default_big_14.png' %}"/></dt>
    </dl>
    <div class="userdetail">
    	<dl>
            <dt><img width="80" height="80" src="{% static 'media/image/2016/12/default_big_14.png' %}"/></dt>
            <dd>
                <h2>django</h2>
                <p>bobby</p>
            </dd>
        </dl>
        <div class="btn">
            <a class="personcenter fl" href="usercenter-info.html">进入个人中心</a>
            <a class="fr" href="/logout/">退出</a>
        </div>
    </div>
</div>
{% else %}
    <a style="color:white" class="fr registerbtn" href="/register/">注册</a>
    <a style="color:white" class="fr loginbtn" href="/login/">登录</a>
{% endif %}
  • 测试用户登录功能(账号密码为超级管理员),登录成功则跳转到主页并且在主页上不显示登录和注册功能而显示用户信息模块;登录不成功则跳转到登录页

4.增加邮箱登录 

  • django 提供的authenticate方法只是针对用使用用户名进行登录,当使用邮箱进行登录时,则会出现异常,博主使用Debug模式启动项目,在视图函数中打断点,然后在登录页面输入邮箱和密码后点击登录,则debug显示authenticate方法返回的user的值为None

  • 要想使用邮箱进行登录,则需要自定义authenticate方法即可,首先在settings中设置AUTHENTICATION_BACKENDS为我们自定义的类,而这个类需要继承django.contrib.auth.backends中的ModelBackend类才能去重写父类的authenticate方法,具体实现如下
class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            # 使用get查询唯一条件,使用django模型中提供的的Q类对查询条件or查询,通俗来说就是满足username或者email其中一个即可
            user = UserProfile.objects.get(Q(username=username) | Q(email=username))
            if user.check_password(password):
                return user
        except Exception as e:
            return None
  • 在users/views中定义CustomBackend类后,还需要在settings配置AUTHENTICATION_BACKENDS
AUTHENTICATION_BACKENDS = (
    'users.views.CustomBackend',
)
  • Debug测试使用邮箱登录成功调用重写的authenticate方法,并返回user对象

  • 当user为None表示用户名或者密码错误,即需要在页面上提示用户错误信息,所以在视图函中返回登录页面时,需要向模板中传递错误信息
if user is not None:
    login(request, user)
    return render(request, "index.html")
else:
    return render(request, "login.html", {"err_msg":"用户名或密码错误"})
  • 紧接着在登录模板文件中打印出此错误信息
<div class="error btns login-form-tips" id="jsLoginTips">{{ err_msg }}</div>
  • 测试邮箱登录以及错误提示显示

5.使用类视图来区分用户请求(跟前面Djnago 电商项目一样)

  • 定义类视图并且继承与View类,在类中编写对应的请求方式函数即可
class LoginView(View):
    """登录"""
    def get(self, request):
        return render(request, "login.html")

    def post(self, request):
        user_name = request.POST.get("username", "")
        pass_word = request.POST.get("password", "")
        user = authenticate(username=user_name, password=pass_word)
        if user is not None:
            login(request, user)
            return render(request, "index.html")
        else:
            return render(request, "login.html", {"err_msg": "用户名或密码错误"})
  • 在根级urls中需进行如下修改,需导入定义的类视图,并在路由中调用该类的as_views方法
url(r'^login/$', LoginView.as_view(), name="login")

6.在后端中进行登录表单信息验证

说明:在用户登录时,为了减少数据库查询操作,那么一个网站会在前端使用js对用户输入的信息进行判断(比如密码长度,是否为空等等);不管前端有没有进行校验判断,后端也必须进行校验判断

  • 在users应用下创建forms.py文件,用于校验用户输入的用户名密码是否合法,在文件中进行如下编写
class LoginFrom(forms.Form):
    """登录表单验证"""
    # username和password变量名要与模板中表单字段名一致
    username = forms.CharField(required=True)
    password = forms.CharField(required=True, min_length=5)
  • 在登录类视图post方法中需要判断登录表单信息验证是否正确,当不正确存在错误时则将表单对象传递到登录模板中
def post(self, request):
    login_form = LoginFrom(request.POST)  # 需传递的是字典对象
    if login_form.is_valid():
        user_name = request.POST.get("username", "")
        pass_word = request.POST.get("password", "")
        user = authenticate(username=user_name, password=pass_word)
        if user is not None:
            login(request, user)
            return render(request, "index.html")
        else:
            return render(request, "login.html", {"err_msg": "用户名或密码错误"})
    else:
        return render(request, "login.html", {"login_form": login_form})
  • 不合法登录验证测试(输入密码小于5个字符)

  • 不合法登录验证测试(密码为空)

7.将表单验证错误信息显示在登录页面中

  • 在login.html模板中需要进行判断,如果后端传递过来的login_form对象中的errors存在username字段则在用户名所在的标签中添加errorput样式,password所在标签也是同样的
<div class="form-group marb20 {% if login_form.errors.username %}errorput{% endif %}">
    <label>用&nbsp;户&nbsp;名</label>
    <input name="username" id="account_l" type="text" placeholder="手机号/邮箱" />
</div>
<div class="form-group marb8 {% if login_form.errors.password %}errorput{% endif %}">
    <label>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</label>
    <input name="password" id="password_l" type="password" placeholder="请输入您的密码" />
</div>
  • 显示错误信息,需要循环遍历并且打印显示错误的字段对应错误提示,最初后面打印的error_msg信息与表单验证错误信息是不共存情况,所以写在一起无所谓
<div class="error btns login-form-tips" id="jsLoginTips">{% for key,error in login_form.errors.items %}{{ error }}{% endfor %}{{ err_msg }}</div>
  • 错误信息登录测试

8.Django 如何通过cookie和session来实现用户自动登录

  • 用户第一次登录成功时在cookies中并没有携带名为sessionid的cookie,那么服务器就会根据登录成功的用户名和密码随机生成一段随机字符串,这段字符串是具有过期时间的,然后将这端字符串sessionid返回给浏览器并存在cookies中;当用户下一次请求时就会携带cookies中保存的sessionid给服务器,服务器根据浏览器发送的sessionid,在数据库django_session表中去进行查询,查询到sessionid对应的数据则自动登录,那么在登录成功后,是怎么将sessionid保存到数据库的呢?在LoginView类视图post请求方法中,login(request, user)这行代码中使用django提供的login方法会将用户登录成功的信息数据生成对应的sessionid保存到数据库表django_session的session_key中,当用户登录成功后,会去查询此sessionid取出用户信息的;如何将sessionid的值转换为用户信息取决于视图中的request,而request可以直接去调用user对象是因为settings中配置的'django.contrib.sessions'的app,查看用户登录成功后,访问主页index页面请求的cookies数据

  • 查看数据库django_sessions表数据,从中可以发现session_key的值与cookies中sessionid的值一致

9.实现注册功能

  • 在前面已经渲染出了注册页面,但这里需要通过类视图中的get方法来对注册模板进行渲染,所以首先需要定义类视图
class RegisterView(View):
    """注册"""
    def get(self, request):
        return render(request, "register.html")
  • 修改根基urls中的注册路由
url(r'^register/$', RegisterView.as_view(), name="register")
  • 在index丶login以及register模板文件中将所有涉及到注册登录链接地址地方进行如下修改
<a style="color:white" class="fr registerbtn" href="{% url 'register' %}">注册</a>
<a style="color:white" class="fr loginbtn" href="{% url 'login' %}">登录</a>

  • 在注册页面设计到验证码,所以需要安装django 第三方工具包captcha

  • 安装captcha完成后,紧接需要将captcha注册到app中
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "users",
    "courses",
    "organization",
    "operation",
    "xadmin",
    "crispy_forms",
    "captcha"
]
  • 在根级urls中将captcha.urls包含进来
 url(r'captcha/',include('captcha.urls'))
  • 生成captcha迁移文件并执行迁移,在数据库中生成对应的数据表

  • 查看生成的captcha数据表

  • 如何在注册页面中显示captcha包生成的验证码,首先在users/forms模块中定义注册表单验证,在表单验证码字段中需要从captcha.fields中去导入CaptchaField类来进行验证,验证码错误提示为英文的invalid,所以需要进行转换为中文提示信息
class RegisterForm(forms.Form):
    '''注册表单验证'''
    email = forms.EmailField(required=True)
    password = forms.CharField(required=True, min_length=5)
    captcha = CaptchaField(error_messages={'invalid': '验证码错误'})
  • 在类视图get方法中需要创建注册表单验证实例化对象
class RegisterView(View):
    """注册"""
    def get(self, request):
        register_form = RegisterForm()
        return render(request, "register.html", {'register_form':register_form})
  • 在注册模板文件form表单中验证码标签下需要打印出后端传递的register_form对象的的captcha方法来显示出验证码图片
<form id="email_register_form" method="post" action="{% url 'register' %}" autocomplete="off">
    <div class="form-group marb20 ">
        <label>邮&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;箱</label>
        <input  type="text" id="id_email" name="email" placeholder="请输入您的邮箱地址" />
    </div>
    <div class="form-group marb8 ">
        <label>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</label>
        <input type="password" id="id_password" name="password" placeholder="请输入6-20位非中文字符密码" />
    </div>
    <div class="form-group marb8 captcha1 ">
        <label>验&nbsp;证&nbsp;码</label>
        {{ register_form.captcha }}
    </div>
    <div class="error btns" id="jsEmailTips"></div>
    <div class="auto-box marb8">
    </div>
    <input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册并登录" />
    {% csrf_token %}
</form>
  • 测试注册页面验证码显示

  • 查看数据表captcha_captchastore生成的验证码数据

  • 在类视图RegisterView中定义post方法,进行注册表单的验证
def post(self, request):
    register_form = RegisterForm(request.POST)
    if register_form.is_valid():
        pass
  • 不合法注册验证(密码小于5)

  • 不合法注册验证(邮箱密码为空)

  • 不合法注册验证(验证码错误)

  • 定义类视图post方法,将用户注册填写的用户名(邮箱)密码保存到数据库中
def post(self, request):
    register_form = RegisterForm(request.POST)
    if register_form.is_valid():
        user_name = request.POST.get("email", "")
        pass_word = request.POST.get("password", "")
        user_profile = UserProfile()
        user_profile.username = user_name  # 用户名
        user_profile.email = user_name  # 邮箱
        user_profile.password = make_password(pass_word)  # 密码
        user_profile.save()

10.发送用户注册激活邮件

  • 因为使用邮箱注册成功时需要向该邮箱发送激活邮件,对注册用户进行激活处理,所以在项目中需要定义发送邮件工具,即在apps目录下创建utils工具包,在工具包下创建email_send模块,在模块中进行发送邮件代码逻辑处理
def random_str(randomlength=8):
    """生成随机字符串"""
    str = ''
    chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
    length = len(chars) - 1
    random = Random()
    for i in range(randomlength):
        str+=chars[random.randint(0, length)]
    return str


def send_register_email(email, send_type="register"):
    """发送邮件"""
    # 将要发送的随机字符串和邮箱地址以及验证码类型先保存到数据库中
    email_record = EmailVerifyRecord()
    code = random_str(16)
    email_record.code = code
    email_record.email = email
    email_record.send_type = send_type
    email_record.save()
    # 定义发送邮件的标题和内容,根据验证码类型send_type对应发送不同的内容
    email_title = ""
    email_body = ""

    if send_type == "register":
        email_title = "慕学在线网注册激活链接"
        email_body = "请点击下面的链接激活你的账号: http://127.0.0.1:8000/active/{0}".format(code)

        send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
        if send_status:
            pass
  • 博主在之前的Django电商项目中注册功能实现邮件激活是通过QQ邮箱进行演示的,而这里博主打算新建个新浪邮箱来进行本项目中账户邮件激活演示,首先进入新浪邮箱开启POP3/SMTP服务如下图配置即可

  • 完成上一步后,需要在settings中配置邮件信息
EMAIL_HOST = "smtp.sina.com"
EMAIL_PORT = 25
EMAIL_HOST_USER = "cdtaogang@sina.com"
EMAIL_HOST_PASSWORD = "xxxxx"
EMAIL_USE_TLS= False
EMAIL_FROM = "cdtaogang@sina.com"
  • 回到注册类视图post方法中,调用定义的邮件发送工具包中的send_register_email方法,进行发送注册账号激活邮件
# 发送激活邮件
send_register_email(user_name, "register")
  • Debug运行项目打断点测试邮件发送是否成功,Debug到post函数中发送调用send_register_email方法时并没有出错

  • 继续Debug查看工具包中的send_register_email方法中调用send_email方法,返回为1表示发送成功

  • 此时查看邮箱已收到邮件,整个注册发送激活邮件逻辑正确

  • 查看数据库userprofile表信息,注册用户成功;因为UserProfile模型类继承的是django user用户类,所以默认is_active为激活状态,正常来说为0未激活,在后面代码逻辑中会进行设置的

  • 当注册成功后则跳转到登录页,失败则跳转到注册页
def post(self, request):
    register_form = RegisterForm(request.POST)
    if register_form.is_valid():
        user_name = request.POST.get("email", "")
        pass_word = request.POST.get("password", "")
        user_profile = UserProfile()
        user_profile.username = user_name  # 用户名
        user_profile.email = user_name  # 邮箱
        user_profile.password = make_password(pass_word)  # 密码
        user_profile.save()

        # 发送激活邮件
        send_register_email(user_name, "register")
        return render(request, "login.html")
    else:
        return render(request, "register.html",{"register_form": register_form})

 11.将注册表单错误信息显示在页面中

  • 跟登录功能一样,在注册模板中当存在不合法表单提交时打印出对应的错误提示,并对其input框添加红框样式显示;这里给邮箱框和密码框设定了value值为当用户输入不合法时,则在输入框中显示上一次的输入
<form id="email_register_form" novalidate method="post" action="{% url 'register' %}" autocomplete="off">
    <div class="form-group marb20 {% if register_form.errors.email %}errorput{% endif %}">
        <label>邮&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;箱</label>
        <input  type="text" id="id_email" name="email" value="{{ register_form.email.value }}" placeholder="请输入您的邮箱地址" />
    </div>
    <div class="form-group marb8 {% if register_form.errors.password %}errorput{% endif %}">
        <label>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</label>
        <input type="password" id="id_password" name="password" value="{{ register_form.password.value }}" placeholder="请输入5-20位非中文字符密码" />
    </div>
    <div class="form-group marb8 captcha1 {% if register_form.errors.captcha %}errorput{% endif %}">
        <label>验&nbsp;证&nbsp;码</label>
        {{ register_form.captcha }}
    </div>
    <div class="error btns" id="jsEmailTips">{% for key,error in register_form.errors.items %}{{ error }}{% endfor %}{{ err_msg }}</div>
    <div class="auto-box marb8">
    </div>
    <input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册并登录" />
    {% csrf_token %}
</form>
  • 注册功能提交错误表达测试

12.定义账户激活类视图,完成账户的激活

  • 在注册类视图post方法中需要设置用户的激活状态为False,表示未激活
user_profile.is_active = False
  • 在users/views中定义账户激活类视图
class AciveUserView(View):
    """账户激活"""
    def get(self, request, active_code):
        # 根据邮件中的链接地址获取地址中的随机字符串到数据库emailverifyrecord表中获取此数据
        all_records = EmailVerifyRecord.objects.filter(code=active_code)
        # 如果查询到数据则进行遍历获取record对象中的email,再根据email到用户信息表中查询user对象,设置此对象的is_active字段为True(激活)
        # 最后返回到登录页面
        if all_records:
            for record in all_records:
                email = record.email
                user = UserProfile.objects.get(email=email)
                user.is_active = True
                user.save()
        return render(request, "login.html")
  • 在根级urls中定义账户激活的路由,()进行获取正则匹配到的参数保存到active_code中
url(r'^active/(?P<active_code>.*)/$',AciveUserView.as_view(), name="user_active")
  • 在登录类视图post方法中则需要判断当前用户的is_active字段的值是否为True
def post(self, request):
    login_form = LoginFrom(request.POST)  # 需传递的是字典对象
    if login_form.is_valid():
        user_name = request.POST.get("username", "")
        pass_word = request.POST.get("password", "")
        user = authenticate(username=user_name, password=pass_word)
        if user is not None:
            if user.is_active:
                login(request, user)
                return render(request, "index.html")
            else:
                return render(request, "login.html", {"err_msg": "用户未激活"})
        else:
            return render(request, "login.html", {"err_msg": "用户名或密码错误"})
    else:
        return render(request, "login.html", {"login_form": login_form})
  • 删除userprofile用户表和emailverifyrecord邮箱验证表cdtaogang@sina.com账户信息(因为之前还未设置用户注册时is_active字段为False),重新进行注册登录验证

  • 还是使用之前的新浪邮箱进行注册,注册成功后查看数据表userprofile信息中is_active字段显示为0

  • 登录以上注册账户进行测试,则提示账户未激活

  • 查看邮件中激活邮件,访问激活链接地址,调用激活类视图,对此注册用户进行激活,最后跳转到登录页面

 

  • 查看数据表userprofile信息

13.完善注册功能

  • 一个邮箱只能允许被注册一次,即在注册类视图post方法中需要将用户填写的邮箱拿到后台数据库中进行查询,如果查询到说明此邮箱已经被注册过了,那么就返回错误信息提示,并返回注册页面,需要注意的是注册模板中需要register_form值,所以需要进行传递,不传递则,不会提示错误信息
# 判断邮箱是否已经注册过
if UserProfile.objects.filter(email=user_name):
    return render(request, "register.html", {"register_form": register_form, "err_msg": "此邮箱已被注册过"})
  • 测试使用已经注册成功的邮箱进行二次注册

  • 在激活链接视图中当激活链接中的active_code不存在时,则返回错误页面信息
class AciveUserView(View):
    """账户激活"""
    def get(self, request, active_code):
        # 根据邮件中的链接地址获取地址中的随机字符串到数据库emailverifyrecord表中获取此数据
        all_records = EmailVerifyRecord.objects.filter(code=active_code)
        # 如果查询到数据则进行遍历获取record对象中的email,再根据email到用户信息表中查询user对象,设置此对象的is_active字段为True(激活)
        # 最后返回到登录页面
        if all_records:
            for record in all_records:
                email = record.email
                user = UserProfile.objects.get(email=email)
                user.is_active = True
                user.save()
        else:
            return render(request, "active_fail.html")
        return render(request, "login.html")
  • 在templates目录下创建active_fail模板文件,在该文件中可自定义页面数据,主要是为了提示用户链接地址错误不存在之类的
<div class="txtbox">
    <p>对不起,您请求的页面不存在、或已被删除、或暂时不可用</p>
    <p class="paddingbox">请点击以下链接继续浏览网页</p>
    <p><a style="cursor:pointer" onclick="history.back()">返回上一页面</a></p>
    <p><a href="{% url 'index' %}">返回网站首页</a></p>
</div>
  • 测试访问错误的激活链接地址(为了方便演示,换了火狐浏览器)

二丶找回密码(忘记密码)

1.显示忘记密码页面

  • 定义忘记密码类视图get函数
class ForgetPwdView(View):
    """找回密码"""
    def get(self, request):
        return render(request, "forgetpwd.html")
  • 在根级urls中配置路由
url(r'^forget/$', ForgetPwdView.as_view(), name="forget_pwd")
  • 将static目录下的forgetpwd.html模板文件拷贝到templates目录下,然后在login模板文件中修改忘记密码链接地址
<a class="fr" href="{% url 'forget_pwd' %}">忘记密码?</a>
  • 测试显示忘记密码页面

  • 修改forgetpwd模板文件中的静态资源链接地址,再次刷新页面

2.在忘记密码页面显示验证码图片

  • 定义忘记密码form表单验证(跟注册表单验证逻辑一样)
class ForgetForm(forms.Form):
    """忘记密码表单验证"""
    email = forms.EmailField(required=True)
    captcha = CaptchaField(error_messages={'invalid': '验证码错误'})
  • 在类视图get方法中需要传递表单验证实例化对象到模板中
def get(self, request):
    forget_form = ForgetForm()
    return render(request, "forgetpwd.html", {"forget_form": forget_form})
  • 在forgetpwd模板中,打印验证码图片
<div class="form-group captcha1 marb38">
    <label>验&nbsp;证&nbsp;码</label>
    {{ forget_form.captcha }}
</div>
  • 刷新页面,则成功显示出图片验证码

3.发送重置密码邮件

  • 在类视图中定义post方法,实现重置密码(代码逻辑与注册一样)
def post(self, request):
    forget_form = ForgetForm(request.POST)
    if forget_form.is_valid():
        email = request.POST.get("email", "")
        send_register_email(email, "forget")
        return render(request, "send_success.html")
    else:
        return render(request, "forgetpwd.html", {"forget_form": forget_form})
  • 在forgetpwd模板文件中首先定义表单的请求方式以及地址,然后打印显示错误提示信息和显示错误红框以及在输入框中显示错误输入的邮箱地址(和register模板一样)
<form id="jsFindPwdForm" novalidate method="post" action="{% url 'forget_pwd' %}" autocomplete="off">
    <div class="form-group marb20 {% if register_form.errors.email %}errorput{% endif %}">
        <label>帐&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;号</label>
        <input type="text" id="account" name="email" value="{{ register_form.email.value }}" placeholder="邮箱" />
    </div>
    <div class="form-group captcha1 marb38 {% if register_form.errors.captcha %}errorput{% endif %}">
        <label>验&nbsp;证&nbsp;码</label>
        {{ forget_form.captcha }}
    </div>
    <div class="error btns" id="jsForgetTips">{% for key,error in forget_form.errors.items %}{{ error }}{% endfor %}{{ err_msg }}</div>
    <input type="hidden" name="sms_type" value="1">
    <input class="btn btn-green" id="jsFindPwdBtn" type="submit" value="提交" />
    <p class="form-p" style="bottom:40px;">您还可以<a href="login.html"> [直接登录]</a></p>
    {% csrf_token %}
</form>
  • 在email_send模块send_register_email方法中需要定义发送重置密码的链接地址
elif send_type == "forget":
    email_title = "慕学在线网注册密码重置链接"
    email_body = "请点击下面的链接重置密码: http://127.0.0.1:8000/reset/{0}".format(code)

    send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
    if send_status:
        pass
  • 邮件发送成功后则需要提示用户发送成功,所以需要在templates目录下创建视图方法中返回的send_success模板文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<p style="font-size: 25px;font-style:inherit;color: #3f4724">邮件发送成功,请查收</p>
<a style="text-decoration: none" href="https://mail.sina.com.cn/">登录我的邮箱</a>
</body>
</html>
  • Debug测试忘记密码发送邮件成功

  • 同时Debug测试完成后,则在页面上渲染出send_success模板

  • 点击登录我的邮箱,查看邮件

4.访问重置密码链接地址跳转到密码重置页面

  • 首先定义重置密码类视图get方法(与注册账户激活逻辑大同小异),获取到用户邮箱后,则跳转到密码重置的页面(password_rest.html)
class ResetView(View):
    """重置密码"""
    def get(self, request, active_code):
        # 根据邮件中的链接地址获取地址中的随机字符串到数据库emailverifyrecord表中获取此数据
        all_records = EmailVerifyRecord.objects.filter(code=active_code)
        # 如果查询到数据则进行遍历获取record对象中的email,返回密码重置页面,并将email传递给模板
        # 最后返回到登录页面
        if all_records:
            for record in all_records:
                email = record.email
                return render(request, "password_reset.html", {"email":email})
        else:
            return render(request, "active_fail.html")
        return render(request, "login.html")
  • 将static目录下的password_rest.html模板拷贝到templates目录下,修改模板资源路径这个就不再说了,之前已经演示过了,只需要将类视图传递过来的email,隐藏打印在input标签中
<form id="reset_password_form" action="" method="post">
    <ul>
        <li>
            <span class="">新 密 码 :</span>
            <input type="password" name="password1" id="pwd" placeholder="5-20位非中文字符">
            <i></i>
        </li>
        <input type="hidden" name="email" value="{{ email }}">
        <li>
            <span class="">确定密码:</span>
            <input type="password" name="password2" id="repwd" placeholder="5-20位非中文字符">
            <i></i>
        </li>
        <li class="button">
            <input type="submit" value="提交" >
        </li>
    </ul>
</form>

  • Debug断点测试完成后,页面成功跳转至密码修改页面(password_rest.html)

5.密码修改功能实现

  • 因为密码修改页面,也是form表单提交,所以需要在forms中定义修改密码表单验证(需要注意的是忘记密码是一个表单,同样修改密码也是一个表单,两个表单都是单独页面)
class ModifyPwdForm(forms.Form):
    """修改密码表单验证"""
    password1 = forms.CharField(required=True, min_length=5)
    password2 = forms.CharField(required=True, min_length=5)
  • 定义修改密码类视图post方法,完成密码修改功能逻辑,需要注意的是为什么不在重置密码类视图ResetView下直接定义post方法,因为该类视图的路由规则中需要传递active_code,所以这里需要另外定义类视图来完成修改密码
class ModifyPwdView(View):
    """修改密码"""
    def post(self, request):
        modify_form = ModifyPwdForm(request.POST)
        if modify_form.is_valid():
            pwd1 = request.POST.get("password1", "")
            pwd2 = request.POST.get("password2", "")
            # 该email为模板中隐藏的input标签
            email = request.POST.get("email", "")
            # 当用户两次密码不一致则提示错误信息到页面,一致时则通过用户名也就是邮箱来获取用户信息user对象,设置对象中的密码为用户填写的密码
            # 最后返回到登录页面
            if pwd1 != pwd2:
                return render(request, "password_reset.html", {"email":email, "msg":"密码不一致"})
            user = UserProfile.objects.get(email=email)
            user.password = make_password(pwd2)
            user.save()
            return render(request, "login.html")
        else:
            # 表单验证不通过,则需要获取email邮箱地址,返回给password_reset模板,以及表单对象好用作于密码修改表单错误信息打印
            email = request.POST.get("email", "")
            return render(request, "password_reset.html", {"email":email, "modify_form":modify_form})
  • 在根级urls中配置路由
url(r'^modify_pwd/$', ModifyPwdView.as_view(), name="modify_pwd"),
  •  紧接着在password_rest模板中,定义表单的请求方式以及地址
<form id="reset_password_form" action="{% url 'modify_pwd' %}" method="post">
  • Debug测试密码修改功能,测试密码修改成功

  • Debug测试完成后,页面跳转到登录页面

6.密码修改功能完整测试

说明:由于时间过长所以制作成两部分的动图

  • 第一部分完成重置密码邮件的发送

  • 第二部分访问重置密码链接地址完成密码修改并进行登录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cdtaogang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值