• Django+xadmin打造在线教育平台(三)


    Django+xadmin打造在线教育平台(三)

     

    代码

    github下载

    五、用户注册

     主要实现功能

    • 用户输入邮箱、密码和验证码,点注册按钮
    • 如果输入的不正确,提示错误信息
    • 如果正确,发送激活邮件,用户通过邮件激活后才能登陆
    • 即使注册功能,没有激活的用户也不能登陆

    5.1.初步视图

    users/views.py

    class RegisterView(View):
        '''用户注册'''
        def get(self,request):
            return render(request,'register.html')

     用户以get方式,直接返回注册页面

    5.2.路由设计

    复制代码
    # MxOnline/urls.py
    
    from users.views import RegisterView
    
    
        path('register/',RegisterView.as_view(),name = 'register'),
    复制代码

    urls中。通过类的as_view方法,调用这个View类

    5.3.模板修改

    修改index.html

    点 “注册 ”应该跳到用户注册页面

     <a style="color:white" class="fr registerbtn" href="/register/">注册</a>

    <a style="color:white" class="fr loginbtn" href="/login/">登录</a>

    修改register.html中的静态文件地址

    复制代码
    {% load staticfiles %}
    
    <link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
        <link rel="stylesheet" type="text/css" href="{% static 'css/login.css' %}">
    
    .
    .
    .
    
    <script src="{% static 'js/jquery.min.js' %}" type="text/javascript"></script>
    <script src="{% static 'js/unslider.js' %}" type="text/javascript"></script>
    <script src="{% static 'js/validateDialog.js' %}"  type="text/javascript"></script>
    <script src="{% static 'js/login.js' %}"  type="text/javascript"></script>
    复制代码

    测试一下从index界面点注册能不能跳到register界面

     5.4.验证码

     验证码库:django-simple-captcha,这里面有介绍这个第三方库的使用方法

     安装:

    pip install  django-simple-captcha

    Add captcha to the INSTALLED_APPS in your settings.py

    INSTALLED_APPS = [
        'captcha',
    ]

    Add an entry to your urls.py:

    urlpatterns = [
        path('captcha/',include('captcha.urls')),
    ]

    生成到数据库

    python manage.py makemigrations
    
    python manage.py migrate

    可以看到数据库多了一张表

     在注册页面显示验证码

     定义我们的register form:

    复制代码
    # users/forms.py
    
    from captcha.fields import CaptchaField
    
    class RegisterForm(forms.Form):
        '''注册验证表单'''    
        email = forms.EmailField(required=True)
        password = forms.CharField(required=True,min_length=5)
        # 验证码,字段里面可以自定义错误提示信息
        captcha = CaptchaField()
    复制代码
     forms.py
    通过{{ register_form.captcha }}获取验证码
    <div class="form-group marb8 captcha1 ">
         <label>验&nbsp;证&nbsp;码</label>
         {{ register_form.captcha }}
    </div>

     5.5.完善注册的后台逻辑

    复制代码
    class RegisterView(View):
        '''用户注册'''
        def get(self,request):
            register_form = RegisterForm()
            return render(request,'register.html',{'register_form':register_form})
    
        def post(self,request):
            register_form = RegisterForm(request.POST)
            if register_form.is_valid():
                user_name = request.POST.get('email', None)
                # 如果用户已存在,则提示错误信息
                if UserProfile.objects.filter(email = user_name):
                    return render(request, 'register.html', {'register_form':register_form,'msg': '用户已存在'})
    
                pass_word = request.POST.get('password', None)
                # 实例化一个user_profile对象
                user_profile = UserProfile()
                user_profile.username = user_name
                user_profile.email = user_name
                user_profile.is_active = False
                # 对保存到数据库的密码加密
                user_profile.password = make_password(pass_word)
                user_profile.save()
                send_register_eamil(user_name,'register')
                return render(request,'login.html')
            else:
                return render(request,'register.html',{'register_form':register_form})
    复制代码
     views.py所以代码

    说明:

    • 如果是get请求,直接返回注册页面给用户
    • 如果是post请求,先生成一个表单实例,并获取用户提交的所有信息(request.POST)
    • is_valid()方法,验证用户的提交信息是不是合法
    • 如果合法,获取用户提交的email和password
    • 实例化一个user_profile对象,把用户添加到数据库
    • 默认添加的用户是激活状态(is_active=1表示True),在这里我们修改默认的状态(改为is_active = False),只有用户去邮箱激活之后才改为True
    • 对密码加密,然后保存,发送邮箱,username是用户注册的邮箱,‘register’表明是注册
    • 注册成功跳转到登录界面

    5.6.发送激活邮件

    在Python中已经内置了一个smtp邮件发送模块,Django在此基础上进行了简单地封装,让我们在Django环境中可以更方便更灵活的发送邮件。

    所有的功能都在django.core.mail中。

    首先settings里面设置

    复制代码
    # settings.py
    
    EMAIL_HOST = "smtp.qq.com"  # SMTP服务器主机
    EMAIL_PORT = 25             # 端口
    EMAIL_HOST_USER = "1184405959@qq.com"       # 邮箱地址
    EMAIL_HOST_PASSWORD = "dwjybikexxxxxxxx"    # 密码
    EMAIL_USE_TLS= True
    EMAIL_FROM = "1184405959@qq.com"            # 邮箱地址
    复制代码

    说明:

       EMAIL_HOST = "smtp.qq.com"

       EMAIL_HOST_PASSWORD = "dwjybikexxxxxxxx"

    要想用qq邮箱作为服务器发送邮件,必须先开启SMTP,方法如下:

    1)登录邮箱,找到“设置”-->>“用户”

    2)往下拉找到SMTP服务,点开启,然后点“生成授权码”

    3)可以看到授权码,“EMAIL_HOST_PASSWORD”里面填写的就是下面生成的授权码,而不是你的邮箱密码

     

    在apps目录新建package utils,然后新建一个email_send.py文件

    复制代码
    # apps/utils/email_send.py
    
    from random import Random
    from django.core.mail import send_mail
    
    from users.models import EmailVerifyRecord
    from MxOnline.settings import EMAIL_FROM
    
    # 生成随机字符串
    def random_str(random_length=8):
        str = ''
        # 生成字符串的可选字符串
        chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
        length = len(chars) - 1
        random = Random()
        for i in range(random_length):
            str += chars[random.randint(0, length)]
        return str
    
    # 发送注册邮件
    def send_register_eamil(email, send_type="register"):
        # 发送之前先保存到数据库,到时候查询链接是否存在
        # 实例化一个EmailVerifyRecord对象
        email_record = EmailVerifyRecord()
        # 生成随机的code放入链接
        code = random_str(16)
        email_record.code = code
        email_record.email = email
        email_record.send_type = send_type
    
        email_record.save()
    
        # 定义邮件内容:
        email_title = ""
        email_body = ""
    
        if send_type == "register":
            email_title = "NBA注册激活链接"
            email_body = "请点击下面的链接激活你的账号: http://127.0.0.1:8000/active/{0}".format(code)
    
            # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,发件人邮箱地址,收件人(是一个字符串列表)
            send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
            # 如果发送成功
            if send_status:
                pass
    复制代码

     官方文档:

    def send_mail(subject, message, from_email, recipient_list,
                  fail_silently=False, auth_user=None, auth_password=None,
                  connection=None, html_message=None):

    前面四个参数必须要,后面的参数可以为空

    发送电子邮件的最简单方法是使用 django.core.mail.send_mail()

    subjectmessagefrom_emailrecipient_list参数是必需的。

    • subject:一个字符串。
    • message:一个字符串。
    • from_email:一个字符串。
    • recipient_list:字符串列表,每个字符串都是电子邮件地址。每个成员都recipient_list将在电子邮件的“收件人:”字段中看到其他收件人。
    • fail_silently:一个布尔值。如果是的话Falsesend_mail会提出一个smtplib.SMTPException。有关smtplib可能的例外列表,请参阅文档,所有这些例外都是。的子类 SMTPException
    • auth_user:用于向SMTP服务器进行身份验证的可选用户名。如果没有提供,Django将使用该EMAIL_HOST_USER设置的值 。
    • auth_password:用于验证SMTP服务器的可选密码。如果没有提供,Django将使用该EMAIL_HOST_PASSWORD设置的值 。
    • connection:用于发送邮件的可选电子邮件后端。如果未指定,将使用默认后端的实例。有关 更多详细信息,请参阅电子邮件后端的文档。
    • html_message:如果html_message被提供,所得到的电子邮件将是一个 多部分/替代电子邮件message作为 文本/无格式内容类型和html_message作为 text / html的内容类型。

    返回值将是成功传递消息的数量(可以是01因为它只能发送一条消息)。

     5.7.激活用户

    根据邮箱找到对应的用户,然后设置is_active = True来实现

    复制代码
    # 激活用户
    class ActiveUserView(View):
        def get(self, request, active_code):
            # 查询邮箱验证记录是否存在
            all_record = EmailVerifyRecord.objects.filter(code = active_code)
    
            if all_record:
                for record in all_record:
                    # 获取到对应的邮箱
                    email = record.email
                    # 查找到邮箱对应的user
                    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.html,代码如下:

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <p style="color: red;">链接失效</p>
    </body>
    </html>
    复制代码

    激活邮箱的邮件如下:

    修改login视图

    添加一个判断,用户注册的后,等激活才能登陆

     views.py

    修改register.html

    复制代码
     <form id="email_register_form" method="post" action="{% url 'register' %}" autocomplete="off">
                            <input type='hidden' name='csrfmiddlewaretoken' value='gTZljXgnpvxn0fKZ1XkWrM1PrCGSjiCZ' />
                            <div class="form-group marb20 {% if login_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 login_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="请输入6-20位非中文字符密码" />
                            </div>
                            <div class="form-group marb8 captcha1 {% if login_form.errors.captchal %}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 %}
                                {{ msg }}
                            </div>
                            <div class="auto-box marb8">
                            </div>
                            <input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册并登录" />
                        <input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy' />
                        {% csrf_token %}
                        </form>
    复制代码

     修改的地方说明:

    • value="{{ register_form.email.value }}     
    • value="{{ register_form.password.value }}    注册的用户不用再手动输入一遍邮箱和密码了 
    • {% if login_form.errors.email %}errorput{% endif %}
    • {% if login_form.errors.password %}errorput{% endif %}
    • {% if login_form.errors.captchal %}errorput{% endif %}    提示错误信息并显示红框框
    • {{ register_form.captcha }}    显示验证码

    添加邮件激活的url

    复制代码
    # MxOnline/urls.py
    
    import xadmin
    
    from django.urls import path,include,re_path
    
    from django.views.generic import TemplateView
    from users.views import LoginView,RegisterView,ActiveUserView
    
    
    urlpatterns = [
        path('xadmin/', xadmin.site.urls),
        path('', TemplateView.as_view(template_name='index.html'),name='index'),
        path('login/',LoginView.as_view(),name = 'login'),
        path('register/',RegisterView.as_view(),name = 'register'),
        path('captcha/',include('captcha.urls')),
        re_path('active/(?P<active_code>.*)/',ActiveUserView.as_view(),name='user_active'),
    ]
    复制代码

     

    六、找回密码

    主要需要实现的功能:

    • 用户点“忘记密码”,跳到找回密码页面
    • 在forgetpwd页面,输入邮箱和验证码成功后,发送邮件提醒
    • 通过点击邮件链接,可以重置密码
    • 两次密码输的正确无误后,密码更新成功,跳到登录界面

    6.1.路由设计

    from users.views import ForgetPwdView
    
    urlpatterns = [
        path('forget/',ForgetPwdView.as_view(),name='forget_pwd'),
    ]

    6.2.初步视图函数

    首先也需要个表单

    forms.py

    class ForgetPwdForm(forms.Form):
        '''忘记密码'''
        email = forms.EmailField(required=True)
        captcha = CaptchaField(error_messages={'invalid': '验证码错误'})

    视图函数

    class ForgetPwdView(View):
        '''找回密码'''
        def get(self,request):
            forget_form = ForgetPwdForm()
            return render(request,'forgetpwd.html',{'forget_form':forget_form})

    get方式,直接返回忘记密码的表单

    6.3.模板修改

    修改login.html中的url

    <a class="fr" href="{% url 'forget_pwd' %}">忘记密码?</a>

    把forgetpwd.html拷贝到templates文件下

    修改静态文件路径

    显示验证码

     <div class="form-group captcha1 marb38">
         <label>验&nbsp;证&nbsp;码</label>
         {{ forget_pwd.captcha }}
    </div>

    6.4.添加发送找回密码邮件

    修改utils/email_send.py

    发送类型为“forget”

    复制代码
        if send_type == "forget":
            email_title = "NBA找回密码链接"
            email_body = "请点击下面的链接找回你的密码: http://127.0.0.1:8000/reset/{0}".format(code)
    
            # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,从哪里发,接受者list
            send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
            # 如果发送成功
            if send_status:
                pass
    复制代码
     email_send.py

    6.5.完善找回密码的views

    复制代码
    class ForgetPwdView(View):
        '''找回密码'''
        def get(self,request):
            forget_form = ForgetPwdForm()
            return render(request,'forgetpwd.html',{'forget_form':forget_form})
    
        def post(self,request):
            forget_form = ForgetPwdForm(request.POST)
            if forget_form.is_valid():
                email = request.POST.get('email',None)
                send_register_eamil(email,'forget')
                return render(request, 'send_success.html')
            else:
                return render(request,'forgetpwd.html',{'forget_form':forget_form})
    复制代码

    用户提交邮箱后,提醒成功发送邮件

    新建templates/send_success.html

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <p>邮件已发送,请注意查收</p>
    </body>
    </html>
    复制代码

    修改forgetpwd.html

    复制代码
     <form id="jsFindPwdForm" method="post" action="{% url 'forget_pwd' %}" autocomplete="off">
                        <input type='hidden' name='csrfmiddlewaretoken' value='mymQDzHWl2REXIfPMg2mJaLqDfaS1sD5'/>
                        <div class="form-group marb20 {% if forget_from.errors.email %}errorput{% endif %}">
                            <label>帐&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;号</label>
                            <input type="text" id="account" name="email" value="{{ forget_from.email.value }}"
                                   placeholder="邮箱"/>
                        </div>
                        <div class="form-group captcha1 marb38 {% if forget_from.errors.captchal %}errorput{% endif %}">
                            <label>验&nbsp;证&nbsp;码</label>
                            {{ forget_form.captcha }}
                        </div>
                        <div class="error btns" id="jsForgetTips">
                            {% for key,error in forget_from.errors.items %}
                                {{ error }}
                            {% endfor %}
                            {{ 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>
                        <input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy'/>
                        {% csrf_token %}
                    </form>
    复制代码

    测试一下,输入邮箱和验证码看能不能收到邮件

    6.6.重置密码

    (1)重置密码激活邮箱的url

     re_path('reset/(?P<active_code>.*)/', ResetView.as_view(), name='reset_pwd'),

    (2)写重置密码(get方式)后台逻辑

    复制代码
    class ResetView(View):
        def get(self, request, active_code):
            all_records = EmailVerifyRecord.objects.filter(code=active_code)
            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")
    复制代码

    (3)创建修改密码的form表单

    class ModifyPwdForm(forms.Form):
        '''重置密码'''
        password1 = forms.CharField(required=True, min_length=5)
        password2 = forms.CharField(required=True, min_length=5)

    (4)修改密码的url

    上面那个是激活邮箱的url,有active_code参数,只能写get方式的逻辑。

    这里必须单独新建一个修改密码的url,因为如果以post方式提交的话,post提交的地方跟get方式(url中需要active_code参数)的地址不一样,action="{% url 'modify_pwd' %}

    path('modify_pwd/', ModifyPwdView.as_view(), name='modify_pwd'),

    (5)修改密码的后台逻辑

    复制代码
    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 = request.POST.get("email", "")
                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 = request.POST.get("email", "")
                return render(request, "password_reset.html", {"email":email, "modify_form":modify_form })
    复制代码

    (6)修改password_reset.html

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="renderer" content="webkit">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
        <title>密码修改</title>
        <link rel="stylesheet" type="text/css" href="/static/css/reset.css">
        <link rel="stylesheet" type="text/css" href="/static/css/animate.css">
        <link rel="stylesheet" type="text/css" href="/static/css/style.css">
    
    <body>
    <div class="wp">
        <div class="resetpassword" id="resetPwdForm">
            <h1>修改密码</h1>
            <p>已经通过验证,请设置新密码</p>
            <form id="reset_password_form" action="{% url 'modify_pwd' %}" method="post">
                <ul>
                    <li class="{% if modify_form.errors.password1 %}errorput{% endif %}">
                        <span class="">新 密 码 :</span>
                        <input type="password" name="password1" id="pwd" placeholder="6-20位非中文字符">
                        <i></i>
                    </li>
                    <input type="hidden" name="email" value="{{ email }}">
                    <li class="{% if modify_form.errors.password2 %}errorput{% endif %}">
                        <span class="">确定密码:</span>
                        <input type="password" name="password2" id="repwd" placeholder="6-20位非中文字符">
                        <i></i>
                    </li>
                    <div class="error btns" id="jsPasswdResetTips">
                        {% for key,error in modify_form.errors.items %}{{ key }}:{{ error }}{% endfor %}{{ msg }}</div>
                    <li class="button">
                        <input type="submit" value="提交">
                    </li>
                </ul>
                {% csrf_token %}
            </form>
        </div>
        <div class="resetpassword" id="reset_password_tips" style="display:none;">
            <h1>修改密码成功,请重新登录</h1>
            <img class="fl" src="/static/images/check2.png">
            <p class="successword">已经成功修改密码,请重新登录</p>
        </div>
    </div>
    </body>
    </html>
    复制代码

    看一下整个流程有没有问题

    首先在login界面点“忘记密码”,跳到forget页面

     

     

    然后填上要找回密码的邮箱和验证码,提交后会收到邮件

    点击链接,跳到修改密码页面

    修改密码后,跳转到login页面

  • 相关阅读:
    MySQL动态添删改列字段
    关于javascript在子页面中函数无法调试问题的解决
    <T> T[] toArray(T[] a);
    MERGE INTO
    eclipse不能新建server
    关于tomcat7下websocket不能使用
    myeclipse启动tomcat报错cannot find a free socket for debugger
    checkbox提交多组数据到action
    Struts2 Action中的方法命名不要以get开头
    浅谈C#中的接口和抽象类
  • 原文地址:https://www.cnblogs.com/syq666/p/8715519.html
Copyright © 2020-2023  润新知