Django项目: 4.用户登录登出功能
一、功能需求分析
1. 登录退出功能分析
-
流程图
-
-
登录页面
-
登录功能
-
退出功能
1. 接口设计
-
接口说明
类目 说明 请求方法 GET url定义 /user/login/
参数格式 无参数 -
返回结果
登录页面
2.后端代码
-
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')
- 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 %}
标签。
注册功能已经开发好了,所以页面的上的立即注册
{% 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">立即注册 ></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. 业务流程
-
判断用户名账号是否为空
-
判断密码是否为空,格式是否正确
-
判断账户与密码是否正确
2.接口设计
接口说明:
类目 | 说明 |
---|---|
请求方法 | POST |
url定义 | /user/login/ |
参数格式 | 表单参数 |
参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
account | 字符串 | 是 | 用户输入的用户名 |
password | 字符串 | 是 | 用户输入的密码 |
remember | 字符串 | 否 | 用户是否选择免登录 |
返回结果:
{ "errno": "0", "errmsg": "OK", }
3.后端代码
-
视图 在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)
- 表单 在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文件
$(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'), ]
# 修改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>