登录注册分析、多方式登录接口
目录
一、登录注册页面分析
# 根据原型图分析出:要写的功能
# 用户名密码登录接口
# 注册功能接口
# 手机号验证码登录接口
# 发送短信验证码接口
# 验证手机号是否存在接口
二、路由
总路由
path('api/v1/user/', include('user.urls')),
分路由:user/urls.py
from django.urls import path
from . import views
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('userinfo', views.UserView, 'userinfo')
urlpatterns = [
]
urlpatterns += router.urls
三、验证手机号是否存在接口
3.1 不同方式验证手机号
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from .models import User
"""方式一"""
class UserView(ViewSet):
# 验证手机号是否存在的接口 ---> get请求 ---> 要操作数据库,但不需要序列化 --> 想要自动生成路由
# ---> 继承ViewSet
@action(methods=['GET'], detail=False)
def check_mobile(self, request, *args, **kwargs):
# get请求,手机号会拼在路径上
# 取出前端传入的手机号
mobile = request.query_patams.get('mobile', None)
if mobile:
user = User.objects.filter(mobile=mobile).first()
if user:
return APIResponse(msg='手机号存在')
else:
return APIResponse(code=101, msg='手机号不存在')
else:
return APIResponse(code=101, msg='手机号没传')
"""方式二:"""
from rest_framework.exceptions import APIException
class UserView(ViewSet):
# 验证手机号是否存在的接口 ---> get请求 ---> 要操作数据库,但不需要序列化 --> 想要自动生成路由
# ---> 继承ViewSet
@action(methods=['GET'], detail=False)
def check_mobile(self, request, *args, **kwargs):
# get请求,手机号会拼在路径上
# 取出前端传入的手机号
mobile = request.query_params.get('mobile', None)
if mobile:
user = User.objects.filter(mobile=mobile).first()
if user:
return APIResponse(msg='手机号存在')
# 前端只要接收到显示状态码不是100,就是手机号没有注册或者手机号错误或者没输手机号
# 对错误,都可以抛异常
raise APIException('手机号不存在')
# return APIResponse('手机号不存在')
"""方式三:"""
class UserView(ViewSet):
# 验证手机号是否存在的接口 ---> get请求 ---> 要操作数据库,但不需要序列化 --> 想要自动生成路由
# ---> 继承ViewSet
@action(methods=['GET'], detail=False)
def check_mobile(self, request, *args, **kwargs):
# get请求,手机号会拼在路径上
# 取出前端传入的手机号
mobile = request.query_params.get('mobile', None)
if mobile:
user = User.objects.filter(mobile=mobile).first()
if user:
return APIResponse(msg='手机号存在')
# 只有手机号存在,并且手机号正确,才会返回数据,手机号不正确就会直接抛异常,就会被全局异常捕获住,后面的情况也就不需要写代码了
3.2 固定写法
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from .models import User
from rest_framework.exceptions import APIException
class UserView(ViewSet):
# 验证手机号是否存在的接口 ---> get请求 ---> 要操作数据库,但不需要序列化 --> 想要自动生成路由
# ---> 继承ViewSet
@action(methods=['GET'], detail=False)
def check_mobile(self, request, *args, **kwargs):
# get请求,手机号会拼在路径上
# 取出前端传入的手机号
try:
# 可以把主要代码写在try中,产生的错误可以主动抛出
mobile = request.query_params.get('mobile')
print(mobile)
User.objects.get(mobile=mobile) # 使用get,有且只有一条才不报错,如果没有或多余一条,就报错
return APIResponse(msg='手机号存在')
except Exception as e:
raise APIException('手机号不存在')
四、后端多方式登录接口
user/views.py
@action(methods=['POST'], detail=False)
# 多方式登录接口---> 要不要序列化类---> 要用序列化类---> 继承的视图类基类
# post请求--->前端携带的数据 {username:xxx,password:123}
def mul_login(self, request, *args, **kwargs):
# 校验逻辑写在序列化类中
ser = self.get_serializer(data=request.data)
# 只要执行它,就会执行 字段自己的校验规则,局部钩子,全局钩子(全局钩子中写验证逻辑,生成token的逻辑)
ser.is_valid(raise_exception=True) # 如果校验失败,会主动抛出异常
username = ser.context.get('username')
icon = ser.context.get('icon')
token = ser.context.get('token')
return APIResponse(username=username, token=token, icon=icon)
user/serializers.py
from .models import User
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from django.db.models import Q
from rest_framework.exceptions import APIException, ValidationError
from django.conf import settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class LoginUserSerializer(serializers.ModelSerializer):
# 字段自己的规则,会走唯一性校验--->就过不了---->必须要重写该字段
username = serializers.CharField(required=True)
class Meta:
model = User
fields = ['username', 'password'] # 只做数据校验--->写校验的字段
def _get_user(self, attrs):
username = attrs.get('username')
password = attrs.get('password')
# user=User.objects.filter(username=username || mobile=username || email=username)
user = User.objects.filter(Q(username=username) | Q(mobile=username) | Q(email=username)).first()
if user and user.check_password(password):
# 说明用户名存在,密码再校验
return user
else:
raise APIException('用户名或密码错误')
def _get_token(self, user):
# jwt的签发
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return token
def validate(self, attrs):
# 验证用户名密码逻辑---->签发token逻辑
# username字段可能是 用户 ,手机号,邮箱--->正则匹配--->换一种方式 使用Q查询
user = self._get_user(attrs)
# 签发token
token = self._get_token(user)
# 把用户,token放在 序列化类的context中【上下文】
# self.username = user.username # 这样写容易污染ser原本的数据属性
self.context['username'] = user.username
# user.icon是个文件对象,直接获取user.icon.url,而传给前端的需要写全地址
self.context[ 'icon'] = settings.BACKEND_URL + user.icon.url
self.context['token'] = token
return attrs