路飞项目 - 登录注册
1 登录注册功能分析
① 多方式登录接口:用户名、手机号、邮箱 + 密码都可以登录
② 发送手机验证码接口 (借助于第三方短信平台)
③ 短信登录接口
④ 注册接口
⑤ 校验手机号是否存在的接口
2 手机号是否存在接口
判断手机号是否存在接口,也就是发送get请求的时候。
通过在 地址的?后面携带的手机号
判断手机号是否存在的接口
2.1 urls.py
分发应用user的路由
from rest_framework.routers import SimpleRouter from . import views router = SimpleRouter() router.register('usermsg', views.UserView, 'usermsg') urlpatterns = [ ] urlpatterns += router.urls
2.2 views.py
视图函数在UserView类中处理
class UserView(GenericViewSet): @action(methods=['GET'],detail=False) def send_sms(self, request, *args, **kwargs): # 从地址栏中获取手机号来发送短信 try: mobile = request.query_params.get('mobile') # get User.objects.get(mobile) except Exception as e: # raise e raise APIException('手机号不存在') return MyResponse(msg='手机号已经存在')
学会通过异常判断来处理,由于我们已经封装了全局异常处理,所以我们直接抛异常,前端也可以拿到定制返回的信息字典,包括 code和msg
3 多方式登录接口
无论使用用户名、邮箱、手机号当做用户名,配合密码都可以登录账号,返回token
3.1 views.py
在视图类中,我们将校验的逻辑放到序列化类中,而视图类中只获取在序列化类中校验后的数据,包括登录成功后返回的username和token,
# 用户功能 class UserView(GenericViewSet): serializer_class = UserLoginSerializer queryset = User.objects.all().filter(is_active=True) # 校验auth_user表中的活跃用户才可以登录 # 使用action装饰器来保证接口的安全 @action(methods=['POST'], detail=False) def login_multiple(self, request, *args, **kwargs): # 获得序列化对象 # ser = UserLoginSerializer() ser = self.get_serializer(data=request.data) # 执行序列化类自己的字段校验、局部钩子、全局钩子 ser.is_valid(raise_exception=True) token = ser.context.get('token') username = ser.context.get('username') # return Response({'code': 100, 'msg': '成功', 'token': 'asfa', 'username': 'xxx'}) # 使用自己封装的Response 这样code和msg会使用默认的 return MyResponse(token=token, username=username)
当
raise_exception
设置为False
时,如果在反序列化过程中遇到错误,序列化器会将错误信息添加到serializer.errors
属性中,并返回一个空的字典或者列表(具体取决于序列化器的类型)。这种方式适用于前端需要对错误信息进行处理的情况。当
raise_exception
设置为True
时,如果在反序列化过程中遇到错误,序列化器会抛出rest_framework.exceptions.ValidationError
异常,该异常包含错误信息。这种方式适用于后端需要对错误进行处理的情况。
3.2 serializers.py
在序列化器中,我们通过在视图类中调用is_valid()
方法,来校验前端传入的数据,但是并不使用序列化器的序列化和反序列化功能柜,
import re from rest_framework import serializers from .models import User from rest_framework.exceptions import APIException import rest_framework_jwt.utils 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 = serializers.CharField() class Meta: model = User fields = ['username', 'password'] # 全局钩子 def validate(self, attrs): # attrs是前端传入的数据,经过字段自己校验和局部钩子校验过后的数据 """ 1 我们要取出前端传入的用户名和密码 2 要判断前端传入的用户名是 手机号、用户名、还是邮箱,结合密码区数据库中查询 3 比对数据库中的数据,签发token 4 比对后的结果返回给前端 """ # 自己编写类方法来获取user和token user = self._get_user(attrs) token = self._get_token(user) # 获取user和token后要通过序列化类的对象中的 context传给视图类 self.context['username'] = user.username self.context['token'] = token return attrs def _get_user(self, attrs): """获取user的逻辑,在这里编写,增加拓展性""" username = attrs.get('username') password = attrs.get('password') # 判断用户的用户名是手机号、邮箱还是、用户名 if re.match(r'^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$', 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): """通过user获取token,通过drf的jwt认证来获取""" payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) return token
由于使用了ModelSerializer
,所以我们在映射的时候,会将AUTH
模块的abtractuser
表,所以由于username字段默认有unique=True
的限制,所以在使用序列化器做序列化的时候会校验不通过,所以我们需要重写username字段
的校验
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY