Django项目: 4.用户登录登出功能

用户登录登出功能

一、功能需求分析

1. 登录退出功能分析

  1. 流程图

     

     

     

     

  2. 功能

    1. 登录页面

    2. 登录功能

    3. 退出功能

二、登录页面

1. 接口设计

  1. 接口说明

    类目说明
    请求方法 GET
    url定义 /user/login/
    参数格式 无参数
  2. 返回结果

    登录页面

2.后端代码

  1. user/views.py代码:

    from django.shortcuts import render
    from django.views import View
    # ....
    
    class LoginView(View):
        """
        登录视图
        """
        def get(self, request):
            return render(request, 'user/login.html')

     

  2. user/urls.py代码:
    from django.urls import path, include
    from . import views
    app_name = 'user'
    
    urlpatterns = [
        path('register/', views.RegisterView.as_view(), name='register'),
        path('login/', views.LoginView.as_view(), name='login'),
    ]

     

3.前端页面代码

1.user/login.html

因为表单需要post请求,所以记得在页面使用{% csrf_token %}标签。

注册功能已经开发好了,所以页面的上的立即注册处的a标签href可以写好

{% extends 'base/base.html' %}
{% load static %}

{% block title %}登录{% endblock title %}
{% block link %}
      <link rel="stylesheet" href="{% static 'css/user/auth.css' %}">
{% endblock link %}

{% block main_start %}
    <!-- container start -->
<main id="container">
  <div class="login-contain">
    <div class="top-contain">
      <h4 class="please-login">请登录</h4>
      <a href="{% url 'user:register' %}" class="register">立即注册 &gt;</a>
    </div>
    <form action="" method="post" class="form-contain">
      <div class="form-item">
        <input type="tel" placeholder="请输入用户名或手机号" name="account" class="form-control" autocomplete="off">
      </div>
      <div class="form-item">
        <input type="password" placeholder="请输入密码" name="password" class="form-control">
      </div>
      <div class="form-item clearfix">
        <label>
          <input type="checkbox" name="remember">
          <span>记住我</span>
        </label>
        <a href="javascript:void(0);" class="forget-password">忘记密码?</a>
      </div>
      <div class="form-login">
        <input type="submit" value="登录" class="login-btn">
      </div>
        {% csrf_token %}
    </form>
  </div>
</main>
<!-- container end -->
{% endblock main_start %}

 

三、登录功能

1. 业务流程

  1. 判断用户名账号是否为空

  2. 判断密码是否为空,格式是否正确

  3. 判断账户与密码是否正确

2.接口设计

接口说明:

类目说明
请求方法 POST
url定义 /user/login/
参数格式 表单参数

参数说明:

参数名类型是否必须描述
account 字符串 用户输入的用户名
password 字符串 用户输入的密码
remember 字符串 用户是否选择免登录

返回结果:

{
    "errno": "0", 
     "errmsg": "OK", 
}

3.后端代码

  1. 视图 在user目录下的views.py文件中定义如下视图:

    class LoginView(View):
        """
        登录视图
        """
        def get(self, request):
            return render(request, 'user/login.html')
    
        def post(self, request):
            form = LoginForm(data=request.POST, request=request)
    
            if form.is_valid():
                return json_response(errmsg='恭喜登录成功!')
            else:
                err_msg_list = []
                for item in form.errors.values():
                    err_msg_list.append(item[0])
                err_msg_str = '/'.join(err_msg_list)
    
                return json_response(errno=Code.PARAMERR, errmsg=err_msg_str)

     

  2. 表单 在user目下的forms.py文件中定义如下表单:
    class LoginForm(forms.Form):
        account = forms.CharField(error_messages={'required': '账户不能为空'})
        password = forms.CharField(max_length=20, min_length=6,
                                   error_messages={
                                       'max_length': '密码长度要小于20',
                                       'min_length': '密码长度要大于6',
                                       'require': '密码不能为空'
                                   })
        remember = forms.BooleanField(required=False)
    
        def __init__(self, *args, **kwargs):
            self.request = kwargs.pop('request', None)
            super().__init__(*args, **kwargs)
    
        def clean_account(self):
            """
            校验用户账户
            :return:
            """
            account = self.cleaned_data.get('account')
            if not re.match(r'^1[3-9]\d{9}$', account) and (len(account)<5 or len(account)>20):
                raise forms.ValidationError('用户账户格式不正确,请重新输入')
            # 一定要return
            return account
    
        def clean(self):
            """
            校验用户名密码,并实现登录逻辑
            :return:
            """
            cleaned_data = super().clean()
            account = cleaned_data.get('account')
            password = cleaned_data.get('password')
            remember = cleaned_data.get('remember')
    
            # 登录逻辑
            user_queryset = User.objects.filter(Q(mobile=account)|Q(username=account))
            if user_queryset:
                user = user_queryset.first()
                if user.check_password(password):
                    if remember:
                        self.request.session.set_expiry(constants.USER_SESSION_EXPIRY)
                    else:
                        self.request.session.set_expiry(0)
                    login(self.request, user)
    
                else:
                    raise forms.ValidationError('用户名密码错误!')
            else:
                raise forms.ValidationError('用户账号不存在,请重新输入!')

    在user文件加下创建constants.py文件定义如下常量

    # 用户session信息过期时间 单位秒 默认14天
    USER_SESSION_EXPIRY = 14*24*60*60

     

4.前端js代码

修改user/login.html中用户账户输入框input的name为account

在static/js/user/下创建login.js文件

js代码如下:

$(function () {
    let $loginBtn = $('.login-btn');    // 获取登录按钮元素
    $loginBtn.click(function (e) {
        e.preventDefault(); // 阻止默认提交
        // 1.校验账户
        let sAccount = $('input[name="account"]').val();
        if (sAccount === ''){
            message.showError('用户账户不能为空');
            return
        }
        if(!(/^\w{5,20}$/).test(sAccount) && !(/^1[3-9]\d{9}$/).test(sAccount)){
            message.showError('用户账户格式不正确,请求重新输入');
            return
        }
        // 2.校验用户输入密码
        let sPassword = $('input[name="password"]').val();
        if(sPassword === ''){
            message.showError('用户密码不能为空');
            return
        }
        // 3.获取用户是否勾选'记住我',勾选为true,否则为false
        let bRemember = $('input[name="remember"]').is(':checked');
        // 4.发送ajax
        $.ajax({
            url: '/user/login/',
            data: {
                account: sAccount,
                password: sPassword,
                remember: bRemember
            },
            type: 'POST',
            dataType: 'json',
            success: function (res) {
                if(res.errno === '0'){
                    message.showSuccess('恭喜, 登录成功!');
                    setTimeout(function () {
                        //注册成功之后重定向到打开登录页面之前的页面
                        if(!document.referrer || document.referrer.includes('/user/login/') || document.referrer.includes('/user/register/')){
                            window.location.href = '/'
                        }else {
                            window.location.href = document.referrer
                        }
                    }, 3000)
                }else{
                    message.showError(res.errmsg)
                }
            },
            error: function (xhr, msg) {
                message.showError('服务器超时,请重试')

            }
        });
    });
});

四、登出功能

1.接口设计

接口说明:

类目说明
请求方法 GET
url定义 /user/logou/
参数格式 无参数

 

2.后端代码

# 在user目录下的views.py文件中定义如下视图:
class LogoutView(View):
    """
    登出视图
    """
    def get(self, request):
        logout(request)
        
        return redirect(reverse('user:login'))
# 在urser目录下的urls.py文件定义如下路由:
from django.urls import path
from . import views
app_name = 'user'

urlpatterns = [
    path('register/', views.RegisterView.as_view(), name='register'),
    path('login/', views.LoginView.as_view(), name='login'),
    path('logout/', views.LogoutView.as_view(), name='logout'),
]

3.前端代码

# 修改templates/base/base.html中的header部分的代码如下
<header id="header">
  <div class="mw1200 header-contain clearfix">
    <!-- logo start -->
    <h1 class="logo">
      <a href="javascript:void(0);" class="logo-title">Python</a>
    </h1>
    <!-- logo end -->
    <!-- nav start -->
    <nav class="nav">
      <ul class="menu">
        <li class="active"><a href="base.html">首页</a></li>
        <li><a href="../course/course.html">在线课堂</a></li>
        <li><a href="../doc/docDownload.html">下载文档</a></li>
        <li><a href="search.html">搜索</a></li>
      </ul>
    </nav>
    <!-- nav end -->
    <!-- login start -->
      <div class="login-box">
          {% if user.is_authenticated %}
            <div class="author">
              <i class="PyWhich py-user"></i>
              <span>{{ user.username }}</span>
              <ul class="author-menu">
                  {% if user.is_staff %}
                  <li><a href="javascript:void(0);">后台管理</a></li>
                  {% endif %}
                  <li><a href="{% url 'user:logout' %}">退出登录</a></li>
              </ul>
            </div>
          {% else %}
            <div>
              <i class="PyWhich py-user"></i>
              <span>
                  <a href="{% url 'user:login' %}" class="login">登录</a> / <a href="{% url 'user:register' %}"
                                                                          class="reg">注册</a>
              </span>
            </div>
          {% endif %}


      </div>
    <!-- login end -->
  </div>
</header>

 

posted @ 2019-09-17 20:35  Tmclri  阅读(929)  评论(0编辑  收藏  举报