1.分析
业务处理流程:
- 判断用户输入的账号是否为空
- 判断用户输入的密码是否为空,格式是否正确
- 判断用户输入的账号与密码是否正确
请求方法:POST
url定义:/user/login/
请求参数:url路径参数
参数 | 类型 | 前端是否必须传 | 描述 |
user_account | 字符串 | 是 | 用户输入的账号可以是手机号也可以是用户名 |
password | 字符串 | 是 | 用户输入的密码 |
remember_me | 字符串 | 是 | 用户输入的“是否记住我” |
注:由于是post请求,在向后端发起请求时,需要附带csrf token
写js和写后端,其实和前面写注册用户名,发送验证码得流程差不多,下面再提几点与前面不同得需要注意的点就行。
首先是remember me功能。
在后台拿到数据之后,就可以开始进行验证,这里我们可以除了可以使用类似于写注册视图那样的验证之外,还可以使用django自带的form表单验证。
首先前部分写login视图,简单参数验证是否为空。
from users.forms import LoginForm
from django.views import View
# 登录页面
class LoginView(View):
"""
这里写登录页面逻辑
"""
def get(self, request):
return render(request, 'users/login.html', context={
'title': '登录页面',
})
def post(self,request):
#接收前端传入的参数
data = request.body
if not data:
return res_json(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
data = json.loads(data.decode())
# 利用form表单进行验证
#
form_login = LoginForm(data=data, request=request)
# 以下信息在调试的时候,可以看得到
# is_authenticated #翻译:已验证的.已登录返回true,未登录返回false #is_anonymous #翻译:匿名的
if form_login.is_valid():
# 用户信息验证成功,使用login方法登录
# authenticate方法验证给出的username和password是否是一个有效用户。如果有效,则返回一个User对象,无效则返回None
user = authenticate(username=data['user_account'], password=data['password'])
login(request, user )
return res_json(errno=Code.OK, errmsg=error_map[Code.OK])
else:
return res_json(errno=Code.LOGINERR,errmsg=error_map[Code.LOGINERR])
在forms.py文件下:
# -* coding: utf-8 -*-
import re
from django import forms
from django.contrib.auth import login
from .models import Users
from django.db.models import Q
from . import constants
class LoginForm(forms.Form):
user_account = forms.CharField()#因为用户账号可能是手机号,也有可能是用户名,在定义时不好约束,这里可以空着
password = forms.CharField(max_length=20, min_length=6,
error_messages={
'min_length': '密码长度大于6',
'max_length': '密码长度小于20',
'required': '密码不能为空',
})
remember = forms.BooleanField(required=False)
def __init__(self, *args, **kwargs):
# 在传入request之后,获取到里面的值之后,request就没什么用了,可以删除掉。
# 而pop就是删除指定字典里面指定的键,然后返回其值。
self.request = kwargs.pop('request')
# 下面这句是引用原来__init__的意思。因为实例化对象时加入了request参数。而原本
# 的__init__里面是没有request参数的。这里取到request参数之后,
# 再调用原来的__init__实例化对象
super().__init__(*args, **kwargs)
#这里验证用户名用的是clean方法,而前面的用户名定义为user_account,这里需要在clean之后加下划线,
# 再加user_account。clean方法是,想要验证哪一个参数,只要在那个参数下前加下划线,然后拼接clean,
# 成为验证那一个参数的方法的名字。
# 这里的user_account和password字段必须和前台传过来的数据的键对应,想验证哪个键的值,就对应写clean_键
def clean_user_account(self):
user_info = self.cleaned_data.get('user_account')
if not user_info:
raise forms.ValidationError('用户名不能为空!')
if not re.match('^1[3-9]\d{9}$', user_info) and not re.match('[\u4e00-\u9fa5\w]{5,20}', user_info):
raise forms.ValidationError('输入的用户名格式错误,请重新输入!')
return user_info
def clean_password(self):
password = self.cleaned_data.get('password')
if not password:
raise forms.ValidationError('密码不能为空')
return password
# 重写clean方法,针对参数进行验证
def clean(self):
# 使用父类的clean方法
cleaned_data = super().clean()
user_info = cleaned_data.get('user_account')
pass_pwd = cleaned_data.get('password')
rmber = cleaned_data['remember']
# Q方法是“或”的意思
user_qs = Users.objects.filter(Q(mobile=user_info) | Q(username=user_info))
if user_qs:
# .first是返回第一个对象
user = user_qs.first()
# 判断密码,check_password是django的auth系统自带的check_password方法
# 不能直接取出密码对比,因为密码在django写入mysql时已经进行加密,得利用它自己的
# 方法验证。
# 设置密码也有自带方法。
if user.check_password(pass_pwd):
if rmber:
self.request.session.set_expiry(constants.SESSION_EXPIRY_TIME)
else:
self.request.session.set_expiry(constants.SESSION_TIME)
# login(self.request, user_info)
else:
raise forms.ValidationError('用户名或密码错误!')
else:
raise forms.ValidationError('用户名不存在,请重新输入!')
return cleaned_data
如果想在html文件中设置什么,需要什么条件的话,在调试的时候,可以看到它返回一个user对象,里面有许多参数,在利用模板时,可以使用上,如:
<div class="login-box">
{% if not user.is_authenticated %}
<div>
<i class="PyWhich py-user"></i>
<span>
<a href="{% url 'users:login' %}" class="login">登录</a> / <a href="{% url 'users:register' %}" class="reg">注册</a>
</span>
</div>
{% else%}
<div class="author">
<img class='img_icon' src="/static/img/浪浪.jpg">
<span class="user_name">{{ user.username }}</span>
{# <span>#}
<ul class="author-menu">
{% if user.is_staff %}
<li class="back_stage"><a href="javascript:void(0);">后台管理</a></li>
{% endif %}
<li class="logout"><a href="javascript:void(0);">退出登录</a></li>
</ul>
{# </span>#}
</div>
{% endif %}
</div>
而登出则更简单,使用django自带的logout方法,只需把request传进去即可。