第6章 用户注册功能实现

慕课网《强力django+杀手级xadmin 打造上线标准的在线教育平台》 学习笔记


本章主要内容:
+ 完成用户注册相关的功能, 包括登录、注册、找回密码等功能
+ 本章会深入session和cookie的机制以及通过django form对表单进行验证。注册和找回密码会通过图片验证码验证以及通过邮箱验证方式完成


用户登录

  • 配置static静态文件的路径
    这两个表示:当URL匹配到/static/时,则到STATICFILES_DIRS 下寻找
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

扩展登录验证函数

由于默认的验证函数authenticate(username, password)只能验证username和password,但是我们需要验证username & password 和 email & password,我们可以通过扩展authenticate,然后修改默认的backend

  • 在users.views中
class CustomBackend(ModelBackend):
    def authenticate(self, username=None, password=None, **kwargs):
        try:
            # 通过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
  • 在settings中修改默认的backend
AUTHENTICATION_BACKENDS = (
    'users.views.CustomBackend',
)

表单验证

设置一些规则,验证从前台传来的表单是否合法
产生的错误信息存放于_errors中,在前台可查看

class LoginForm(forms.Form):
    username = forms.CharField(required=True)
    password = forms.CharField(required=True, min_length=5)

定义一个登陆类

继承View

class LoginView(View):
    def get(self, request):
        return render(request, "login.html", {})

    def post(self, request):
        login_form = LoginForm(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 HttpResponseRedirect(reverse("index"))
                else:
                    return render(request, "login.html", {"msg":"用户未激活!"})
            else:
                return render(request, "login.html", {"msg":"用户名或密码错误!"})
        else:
            return render(request, "login.html", {"login_form":login_form})
  • urls.py
   url('^login/$', LoginView.as_view(), name="login"),

错误信息提示

将 login_form.errors.items 中所有的错误信息输出

<div class="fl form-box">
        <h2>帐号登录</h2>
        <form action="/login/" method="post" autocomplete="off">
            <input type='hidden' name='csrfmiddlewaretoken' value='mymQDzHWl2REXIfPMg2mJaLqDfaS1sD5' />
            <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>

            <!-- 将所有错误信息输出 -->
            <div class="error btns login-form-tips" id="jsLoginTips">{% for key,error in login_form.errors.items %}{{ error }}{% endfor %}{{ msg }}</div>

             <div class="auto-box marb38">
                <a class="fr" href="{% url 'forget_pwd' %}">忘记密码?</a>
             </div>
             <input class="btn btn-green" id="jsLoginBtn" type="submit" value="立即登录 > " />
        {% csrf_token %}
        </form>
        <p class="form-p">没有慕学在线网帐号?<a href="register.html">[立即注册]</a></p>
    </div>
</div>

这里写图片描述

这里写图片描述


如何理解HTTP协议的“无连接,无状态”特点?
深入解析Cookie技术

这里写图片描述

Django session源码阅读
django sessions(会话)

这里写图片描述


用户注册

这里写图片描述

django验证码插件

Django Simple Captcha : https://github.com/mbi/django-simple-captcha
文档 : http://django-simple-captcha.readthedocs.io/en/latest/

这里写图片描述

验证注册表单

error_messages定制错误信息

class RegisterForm(forms.Form):
    email = forms.EmailField(required=True)
    password = forms.CharField(required=True, min_length=5)
    captcha = CaptchaField(error_messages={"invalid":u"验证码错误"})

注册的view

from django.contrib.auth.hashers import make_password

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", "")
            if UserProfile.objects.filter(email=user_name):
                return render(request, "register.html", {"register_form":register_form, "msg":"用户已经存在"})
            pass_word = request.POST.get("password", "")
            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()

            #写入欢迎注册消息
            user_message = UserMessage()
            user_message.user = user_profile.id
            user_message.message = "欢迎注册慕学在线网"
            user_message.save()

            send_register_email(user_name, "register")
            return render(request, "login.html")
        else:
            return render(request, "register.html", {"register_form":register_form})
  • urls.py配置
    url('^register/$', RegisterView.as_view(), name="register"),
    url(r'^captcha/', include('captcha.urls')),

 前台提示

<form id="email_register_form" 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="请输入6-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 %}{{ msg }}</div>
    <div class="auto-box marb8">
    </div>
    <input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册并登录" />
{% csrf_token %}
</form>

验证码邮件

  • model
class EmailVerifyRecord(models.Model):
    code = models.CharField(max_length=20, verbose_name=u"验证码")
    email = models.EmailField(max_length=50, verbose_name=u"邮箱")
    send_type = models.CharField(verbose_name=u"验证码类型", choices=(("register",u"注册"),("forget",u"找回密码"), ("update_email",u"修改邮箱")), max_length=30)
    send_time = models.DateTimeField(verbose_name=u"发送时间", default=datetime.now)

    class Meta:
        verbose_name = u"邮箱验证码"
        verbose_name_plural = verbose_name

    def __unicode__(self):
        return '{0}({1})'.format(self.code, self.email)
  • 发送邮件逻辑
    三种类型的邮件
# -*- coding: utf-8 -*-
__author__ = 'bobby'
__date__ = '2016/10/30 22:11'
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(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()
    if send_type == "update_email":
        code = random_str(4)
    else:
        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 = "慕学在线网注册激活链接"
        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
    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
    elif send_type == "update_email":
        email_title = "慕学在线邮箱修改验证码"
        email_body = "你的邮箱验证码为: {0}".format(code)

        send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
        if send_status:
            pass
  • 发送邮件前需要先在settings中配置邮箱信息
    注意:需要先开启邮箱的SMTP服务
EMAIL_HOST = "smtp.sina.com"
EMAIL_PORT = 25
EMAIL_HOST_USER = "projectsedu@sina.com"
EMAIL_HOST_PASSWORD = "admin123"
EMAIL_USE_TLS= False
EMAIL_FROM = "projectsedu@sina.com"

激活用户

  • 业务逻辑
class AciveUserView(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
                user = UserProfile.objects.get(email=email)
                user.is_active = True    # 修改用户状态
                user.save()
        else:
            return render(request, "active_fail.html")
        return render(request, "login.html")

找回密码

  • 验证表单
class ForgetForm(forms.Form):
    email = forms.EmailField(required=True)
    captcha = CaptchaField(error_messages={"invalid":u"验证码错误"})
  • 业务逻辑
class ForgetPwdView(View):
    def get(self, request):
        forget_form = ForgetForm()
        return render(request, "forgetpwd.html", {"forget_form":forget_form})

    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})
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值