(根据居然老师直播课内容整理)
一、用户注册业务逻辑分析
- 用户输入地址后,获取注册页面
- 用户输入用户名,前端应检查此用户名是否注册过;
- 两次密码必须输入一致,否则前端应控制重新输入
- 前端会验证手机号码是否答合规范
- 图形验证码会进行验证,正确后,获取短信验证码才应生效
- 短信验证码都正确后,才能提交注册
- 以上都正确后,后端才会进行处理注册请求
- 注册请求通过form表单POST发送数据到后端
- 注册视图接收请求后,接收数据
- 校验数据,如果数据有误或不符合规范,直接返回到登录界面,并发送错误信息
- 数据校验无误后,将保存数据:数据保存到mysql数据库中
- 将状态保存到session中
- 将注册结果返回到前端
二、用户注册接口设计和定义
1、设计接口基本思路
- 对于接口的设计,我们要根据具体的业务逻辑,设计出适合业务逻辑的接口。
- 设计接口的思路:
1.1 分析要实现的业务逻辑:
- 明确在这个业务中涉及到几个相关子业务。
- 将每个子业务当做一个接口来设计。
1.2 分析接口的功能任务,明确接口的访问方式与返回数据:
- 请求方法(如GET、POST、PUT、DELETE等)。
- 请求地址。
- 请求参数(如路径参数、查询字符串、表单、JSON等)。
- 响应数据(如HTML、JSON等)。
2、用户注册接口设计
- 用户注册这个业务可能涉及以下几个子业务
- 用户名是否注册过
- 图形验证码是否正确
- 发送手机验证码
- 用户正常注册
- 下面着重介绍用户正常注册这个子业务接口设计
2.1 请求方式
选项 |
方案 |
请求方法 |
POST |
请求地址 |
/register/ |
2.2 请求参数:表单参数
参数名 |
类型 |
是否必传 |
说明 |
username |
string |
是 |
用户名 |
password |
string |
是 |
密码 |
password2 |
string |
是 |
确认密码 |
mobile |
string |
是 |
手机号 |
sms_code |
string |
是 |
短信验证码 |
allow |
string |
是 |
是否同意用户协议 |
2.3 响应结果
响应结果 |
响应内容 |
注册失败 |
响应错误提示 |
注册成功 |
重定向到首页 |
3、用户注册接口实现
3.1 用户注册接口定义
from django.shortcuts import render
from django.views import View
class RegisterView(View):
"""用户注册"""
def get(self,request):
"""提供用户注册页面"""
return render(request, 'register.html')
def post(self,request):
"""提供用户注册逻辑"""
pass
3.2 定义校验处理类
- 在./apps/users下定义forms.py,对需要校验的数据进行校验处理
- 对数据进行简单校验:变量名(传递的参数名)=form.CharField(简单校验类型=标准值,错误信息字典)
- 用户名、密码、确认密码、手机对最大长度、最小长度、是否必填进行校验
- 用户名和手机号存在的校验,可以前端用ajax方式校验,此处就不处理
- 图形验证码:不需要校验,图形验证码正确后,才能发送短信验证,否则无法发送短信验证码
- 短信验证码:此片只进行长度和必填进行简单校验,有专门的校验算法判断短信验证码的正确性
- 定义clean(self)函数,扩展数据校验
- 首先调用 基类本身的clean(self)校验函数:cleaned_data = super().clean()
- 再判断两次密码是否一致,
from django import forms
class RegisterForm(forms.Form):
username=forms.CharField(max_length=20,min_length=5,required=True,error_messages={
"max_length": "用户名长度最长为20", "min_length": "用户名最少长度为5","required":"用户名必须填写"})
password = forms.CharField(max_length=20, min_length=8, required=True,error_messages={
"max_length": "密码长度最长为20", "min_length": "密码最少长度为8","required":"密码必须填写"})
password2 = forms.CharField(max_length=20, min_length=8, required=True,error_messages={
"max_length": "确认密码长度最长为20", "min_length": "确认密码最少长度为8","required":"确认密码必须填写"})
mobile = forms.CharField(max_length=11, min_length=11, required=True,error_messages={
"max_length": "手机长度最长为20", "min_length": "手机最少长度为11","required":"手机必须填写"})
sms_code = forms.CharField(max_length=6, min_length=6, required=True,error_messages={
"max_length": "手机长度最长为6", "min_length": "手机最少长度为6","required":"短信验证码必须填写"})
def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get('password')
password2 = cleaned_data.get('password2')
if password != password2:
raise forms.ValidationError('两次密码不一致')
return cleaned_data
3.3 用户注册接口开发
- 接收并校验参数:实例化校验处理类
- 判断校验结果
- 如果校验无误:
- 取出 用户名、密码、手机号
- 保存注册信息到数据库:利用Django提供的用户模型类方法
- 状态保持(暂时不写)
- 重定向返回到首页
- 如果校验有误:
- 取出校验错误信息,生成待返回格式的错误信息
- 返回到注册页面(或首页)
from django.shortcuts import render
from django.views import View
from .forms import RegisterForm
from users.models import User
from django import http
class RegisterView(View):
"""用户注册"""
def get(self,request):
"""提供用户注册页面"""
return render(request, 'register.html')
def post(self,request):
"""提供用户注册逻辑"""
register_form = RegisterForm(request.POST)
if register_form.is_valid():
username = register_form.cleaned_data.get('username')
password = register_form.cleaned_data.get('password')
mobile = register_form.cleaned_data.get('mobile')
try:
User.objects.create_user(username=username, password=password, mobile=mobile)
except Exception as e:
return render(request, 'register.html', {
'register_errmsg': '注册失败'})
return http.HttpResponse('注册成功, 重定向到首页')
else:
print(register_form.errors.get_json_data())
context = {
'forms_errors': register_form.errors
}
return render(request, 'register.html', context=context)
3.4 此处一异常处理
3.4.1 错误信息描述:
如果出现下面错误信息
3.4.2解决方法:
需要检查导包路径
- 将 from .models import User 改为 from users.models import User
- 同时将lgshop 改为 Scoures Root
3.4.3 解决方法二:
- ./lgshop/urls.py
3.5 保存注册数据
- 这里使用Django认证系统用户模型类提供的 create_user() 方法创建新的用户。
- 这里 create_user() 方法中封装了 set_password() 方法加密密码。
3.6 响应注册结果
- 注册成功,重定向到首页(前提是定义首页,步骤如下)
- 创建首页contents应用
- 编写index.html
- 写view方法
- 注册contents应用
3.7 状态保持
- 如果需求是注册成功后即表示用户登入成功,那么此时可以在注册成功后实现状态保持
- 如果需求是注册成功后不表示用户登入成功,那么此时不用在注册成功后实现状态保持
- 状态保持:将通过认证的用户的唯一标识信息(比如:用户ID)写入到当前浏览器的 cookie 和服务端的 session 中。
3.7.1 Django的login()方法(状态保持)
- Django用户认证系统提供了login()方法:封装了写入session的操作,帮助我们快速登入一个用户,并实现状态保持。
- login()位置:django.contrib.auth.init.py文件中。
3.7.2 状态保持 session 数据存储的位置
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "session"
三、用户重复注册验证(后端)
1、用户名重复注册逻辑分析
- 用户注册时,当全部信息输入完成提交后,再告诉用户已经被注册过了,这样的用户体验不友好
- 所以,需要用户名输入框失去焦点且简单验证正确后,向后台发送用户重复注册校验请求,如果重复校验提示用户名已被注册过,需要更换,如果没有注册,什么都不提示
- 这个操作采用ajax进行异步操作即可,提高用户体验
2、用户名重复注册接口设计和定义
2.1 请求方式
选项 |
方案 |
请求方法 |
GET |
请求地址 |
/usernames/(?P[a-zA-Z0-9_-]{5,20})/count/ |
2.2 请求参数:路径参数
参数名 |
类型 |
是否必传 |
说明 |
username |
string |
是 |
用户名 |
2.3 响应结果:JSON
响应结果 |
响应内容 |
code |
状态码 |
errmsg |
错误信息 |
count |
记录该用户名的个数 |
3、后台实现
- 用户名重复注册返回不是html,只需返回一个json就行了
3.1 定义view方法
- 用户名重复注册校验 不应该 用户注册业务里实现,同时接口也不一样,所以在users.view.py 再定义一个UsernameCountView类
- UsernameCountView类只需一个get方法
- 只需要统计一下数据库中有几个username即可,应该只有一个或没有
- 所以,取到数据后,直接返回即可
- 注意:数据模型中用的user基类是django的用户类,注意使用方法
class UsernameCountView(View):
"""判断用户名是否重复注册"""
def get(self,request,username):
"""
:param username: 用户名
:return: 返回用户名是否重复 JSON
"""
try:
count = User.objects.filter(username=username).count()
return http.JsonResponse({
'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})
except Exception as e:
logging.error(e)
return http.JsonResponse({
'code': RETCODE.DBERR, 'errmsg': '数据访问失败', 'count': -1})
3.2 注册路由
re_path(r"^usernames/(?P<username>[a-zA-Z0-9-_]{5,20}/count/$)", views.UsernameCountView.as_view())