注册功能
# 前端传入的数据
{手机号,验证码,密码}
# 后端要验证数据--->序列化类
#遇到的错误
1 注册使用哪个序列化了:get_serializer_class
2 配置文件中debug必须是True,因为咱们有万能验证码--->正常流程这个不需要
3 把code,弹出来,加入用户名,你可以随机生成用户名
4 重写create(可以不重写,把密码设为加密的密码),create_user
5 如果你继承了CreateModelMixin,一定要注意,它会走序列化,所以code字段是只写的
视图类
重写get_serializer_class
class UserView(GenericViewSet, CreateModelMixin):
serializer_class = LoginUserSerializer
def get_serializer_class(self):
if self.action == 'sms_login':
return LoginUserSMSSerializer
elif self.action == 'register' or self.action == 'create':
return UserRegisterSerializer
else:
# return super().get_serializer_class()
return self.serializer_class
方式一:自己写接口
@action(methods=['POST'], detail=False)
# 注册接口
# 自己写的 访问:127.0.0.1:8000/api/v1/user/userinfo/register/ --->post请求即可
def register(self, request, *args, **kwargs):
ser = self.get_serializer(data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
return APIResponse(mag='注册成功')
方式二:继承CreateModelMixin
class UserView(GenericViewSet, CreateModelMixin):
# 访问:127.0.0.1:8000/api/v1/user/userinfo/ --->post请求
# 这样调用Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
# 只要调用serializer.data ,就会走序列化,只要走序列化,会把create返回的user对象 来使用UserRegisterSerializer类做序列化
# 就需要在序列化类中code加write_only
code = serializers.CharField(max_length=4, min_length=4, write_only=True)
方式三:继承CreateModelMixin,重写create方法
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data) # 第一个错误 UserRegisterSerializer
serializer.is_valid(raise_exception=True) # 执行三个校验:字段自己,局部钩子,全局
self.perform_create(serializer)
return APIResponse(msg='注册成功') # 不走序列化了,序列类中得write_only 也就不用了
序列化类
# 注册序列化类,注册需要:1.反序列化保存, 2.校验数据, 3.序列化要不要?存疑
class UserRegisterSerializer(serializers.ModelSerializer):
code = serializers.CharField(max_length=4, min_length=4)
class Meta:
model = User
fields = ['mobile', 'password', 'code'] # code 不是数据库的字段,需要重写
# 如果要限制密码强度,需要写个局部钩子
def _check_code(self, attrs):
mobile = attrs.get('mobile')
code = attrs.get('code')
old_code = cache.get('send_sms_code_%s' % mobile)
if not (code == old_code or (settings.DEBUG and code == '8888')): # 第二个错误:debug忘了设为True
raise APIException("验证码错误")
def _pre_save(self, attrs): # {mobile:122222,code:8888,password:123}
attrs.pop('code')
attrs['username'] = attrs.get('mobile') # 默认用户名就是手机号 可以随机生成用户名 随机生成有意义的名字( Faker)
def validate(self, attrs):
# 写逻辑
# 1 校验验证码是否正确
self._check_code(attrs)
# 2 入口前准备 ---> code不是数据库字段,不能入库,username是数据库字段必填,这里没有,写成默认
self._pre_save(attrs)
return attrs
def create(self, validated_data): # {mobile:122222,password:123,username:名字}
# 为什么要重写create? 因为密码人家是加密的,也可以在全局钩子中使用check_password将密码加密
# User.objects.create(**validated_data) # 密码是明文,必须重写
user = User.objects.create_user(**validated_data) # 保存成功,密码就是加密的
return user