登录、注册功能分析
# 接口分析 1 校验手机号是否存在接口 2 多方式登录接口:用户名/手机号/邮箱 + 密码都可以登录 3 发送手机验证码接口(借助于第三方短信平台) 4 短信登录接口 5 注册接口
校验手机号是否存在接口
视图类
视图类初级版
from .models import User from rest_framework.viewsets import GenericViewSet from rest_framework.decorators import action from utils.common_response import APIResponse class UserView(GenericViewSet): @action(methods=['post'],detail=False) def send_sms(self,request,*args,**kwargs): mobile = request.query_params.get('mobile') if mobile: user=User.objects.filter(mobile=mobile).first() if user: return APIResponse(code=100,msg='手机号存在',exist=True) else: return APIResponse(code=100, msg='手机号不存在',exist=False) else: return APIResponse(code=999,msg='手机号必填')
视图类代码优化方案一
因为已经做了全局异常处理,主动抛异常也可以,抛异常不是return,而是raise
from .models import User from rest_framework.viewsets import GenericViewSet from rest_framework.decorators import action from utils.common_response import APIResponse from rest_framework.exceptions import APIException from .serilizer import UserLoginSerializer class UserView(GenericViewSet): serializer_class = UserLoginSerializer queryset = User.objects.filter(is_active=True).all() @action(methods=['get'],detail=False) def send_sms(self,request,*args,**kwargs): try: mobile = request.GET.get('mobile') if mobile: # 用get方法来查询一个数据库里不存在的记录,程序会报错,我们做了全局异常处理,这里会被捕获 User.objects.get(mobile=mobile) else: raise APIException('手机号必填') except Exception as e: return APIResponse(code=777,msg=str(e)) return APIResponse(code=100, msg='手机号存在')
视图类代码优化方案二
class UserView(GenericViewSet): serializer_class = UserLoginSerializer queryset = User.objects.filter(is_active=True).all() @action(methods=['get'], detail=False) def send_sms(self, request, *args, **kwargs): try: mobile = request.GET.get('mobile') User.objects.get(mobile=mobile) except Exception as e: return APIResponse(code=777, msg=str(e)) return APIResponse(code=100, msg='手机号存在')
路由
总路由
from django.urls import path,include path('api/v1/user/',include('home.urls'))
子路由
from rest_framework.routers import SimpleRouter from . import views router = SimpleRouter() # 访问 http://127.0.0.1:8000/api/v1/user/userinfo/send_sms router.register('userinfo', views.UserView, 'userinfo') urlpatterns = [ ] urlpatterns += router.urls
多方式登录接口
逻辑分析
1.取出前端传入的用户名和密码 2.通过用户名和密码去数据库查询用户 3.如果查询到,签发token 4.返回给前端登录成功
序列化类
import re from .models import User from rest_framework import serializers from rest_framework.exceptions import APIException from rest_framework_jwt.settings import api_settings jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER # 这个序列化类用来校验字段,不用来做序列化和反序列化 class UserLoginSerializer(serializers.ModelSerializer): # 重写username字段,把原来的校验规则去掉 username = serializers.CharField() class Meta: model = User # username映射过来,是唯一的,字段自己的校验就过不了 fields = ['username','password'] def validate(self, attrs): """ 1.取出前端传入的用户名和密码 2.通过用户名和密码去数据库查询用户 3.如果查询到,签发token 4.返回给前端登录成功 """ # attrs是前端传入的数据,经过字段自己校验和局部钩子校验过后的数据 user=self._get_user(attrs) token=self._get_token(user) # 把用户名和token放到ser的context中 self.context['token']=token self.context['username']=user.username return attrs def _get_user(self,attrs): username=attrs.get('username') password=attrs.get('password') if re.match(r'^1[3-9][0-9]{9}$',username): user = User.objects.filter(mobile=username).first() elif re.match(r'^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$',username): user=User.objects.filter(email=username).first() else: user = User.objects.filter(username=username).first() if user and user.check_password(password): return user else: # 用户不存在或密码错误 这里的代码,还是在全局钩子中执行,全局钩子校验失败,要抛异常,所以在这抛异常 raise APIException('用户不存在或密码错误') def _get_token(self,user): payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) return token
视图类
class UserView(GenericViewSet): queryset = User.objects.filter(is_active=True).all() serializer_class = UserLoginSerializer @action(methods=['POST'],detail=False) def login_mul(self,request): # 序列化类对象时,可以传入context字典 # context是视图类和序列化类沟通的桥梁 # 有了序列化类对象,通过对象.context就可以拿到值 ser = self.get_serializer(data=request.data) ser.is_valid(raise_exception=True) # 执行这句话,会执行字段自己校验,局部钩子、全局钩子 token=ser.context.get('token') username = ser.context.get('username') return APIResponse(token=token,username=username)
标签:username,登录,get,mobile,token,user,注册,import From: https://www.cnblogs.com/chen-ao666/p/17180515.html