|
# 1、频率限制类()
继承SimpleRateThrottle,scope,重写get_cache_key方法:返回什么就医什么作为key限制,setting中配置
# 2、手机号验证码登录,手机号和验证码
[视图类代码]
class LoginView(ViewSet):
# 多方式登录,手机,名字,邮箱
@action(methods=['POST'],detail=False)
def login(self,request,*args,**kwargs):
ser=serializer.UserSerializer(data=request.data)
if ser.is_valid():
token=ser.context['token']
username=ser.context['user'].username# ser.context['user'] 拿到user对象
return APIResponse(token=token,username=username)
else:
return APIResponse(code=0,msg=ser.errors)
# 单纯校验手机号是否合法,不是登录功能
@action(methods=['GET'],detail=False) # POST请求也可以,因为装饰器的路径不一样,但是为了练一下get的请求方法
def check_telephone(self,request,*args,**kwargs):
telephone=request.query_parms.get('telephone')
if not re.match('^1[3-9][0-9]{9}$',telephone):
return APIResponse(code=0,msg='手机号不合法')
try:
models.User.objects.get(telephone=telephone)
return APIResponse(result=True)
except:
return APIResponse(result='当前手机号不存在') # APIResponse中我们设置了result如果没有就不会添加到dic给data字段了
# 非密码,验证码登录
@action(methods=['POST'],detail=False)
def code_login(self,request,*args,**kwargs):
ser=serializer.CodeUserSerializer(data=request.data)
if ser.is_valid():
token=ser.context['token']
username=ser.context.username
return APIResponse(token=token,username=username)
else:
return APIResponse(code=0,msg=ser.errors)
-----------------------------------------------------------------------------------------------------------------------
[序列化代码(主要逻辑)]
class UserSerializer(serializers.ModelSerializer):
username=serializers.CharField()
class Meta:
model =models.User
fields=['username','password','id']
extra_kwargs={
'id':{'read_only':True},
'password':{'write_only':True},
}
def validate(self, attrs):
user=self._get_user(attrs)
# 签发token
token =self._get_token(user)
# 放到context中可以在视图类中取出来
self.context['token']=token
self.context['user']=user
def _get_user(self,attrs):
username = attrs.get('username')
password = attrs.get('password')
# 多种登录方式
import re
if re.match('^1[3-9][0-9]{9}$', username):
user = models.User.objects.filter(telephone=username).first()
elif re.match('^.+@.+$', username): # 邮箱登录
user = models.User.objects.filter(email=username).first()
else:
user = models.User.objects.filter(username=username).first()
if user:
ret = user.check_password(password)
if ret:
return user
else:
raise ValidationError('密码错误')
else:
raise ValidationError('用户名不存在')
def _get_token(self,user):
from rest_framework_jwt.serializers import jwt_payload_handler,jwt_encode_handler
payload=jwt_payload_handler(user) # 通过user对象获得payload(字典)
token=jwt_encode_handler(payload)# 通过payload获得token
return token
class CodeUserSerializer(serializers.ModelSerializer):
code=serializers.CharField()
class Meta:
model =models.User
fields=['telephone','code']
def validate(self, attrs):
user=self._get_user(attrs)
# 签发token
token =self._get_token(user)
# 放到context中可以在视图类中取出来
self.context['token']=token
self.context['user']=user
return attrs
def _get_user(self,attrs):
telephone = attrs.get('telephone')
code = attrs.get('code')
# 取出原来的code
cache_code=cache.get(settings.PHONE_CAHCE_KEY%telephone)
if cache_code==code:
if re.match('^1[3-9][0-9]{9}$', telephone):
user = models.User.objects.filter(telephone=telephone).first()
if user:
# 把使用过的验证码删除
cache.set(settings.PHONE_CAHCE_KEY%telephone,'')
return user
else:
raise ValidationError('用户不存在')
else:
raise ValidationError('手机号不合法')
else:
raise ValidationError('验证码错误')
def _get_token(self,user):
from rest_framework_jwt.serializers import jwt_payload_handler,jwt_encode_handler
payload=jwt_payload_handler(user) # 通过user对象获得payload(字典)
token=jwt_encode_handler(payload)# 通过payload获得token
return token
-----------------------------------------------------------------------------------------------------------------------
# 3、注册接口:
-1、为什么继承了GenericViewSet和CreateModelMixin分析
-1、首先是注册接口要保存数据所以是要Create方法
-2、要操作数据库和序列化器保存数据所以是GenericAPIView
-3、又想让路由可以自动注册所以变成GenericAPIView→GenericViewSet
-2、一定要写queryset和serializer_class
-3、序列化类=》校验字段
-class Meta(传给前端的字段)=》注意传给前端不想让前端看到的字段可以携程write_only
-def validate(字段的校验,全局好写一点)
-取缓存,校验验证码(可以自己写个验证码)
-4、重写create,因为model继承的是AbstractUser,存密码的时候是明文,所以要重写create方法
-5、在序列化类中可以重写create方法,可以控制注册接口返回的参数
-调用父类的super().create
-返回的是序列化字段对应的字典
-username=response.data.get('key')
-return
[试图类代码实现]
class RegisterView(GenericViewSet,CreateModelMixin):
queryset = models.User.objects.all()
serializer_class =serializer.UserRegisterSerializer
# 为了自定义响应的报文信息,重写create方法(CreateModelMixin方法的)
def create(self, request, *args, **kwargs): # 原生父类的create方法
ser=self.get_serializer(date=request.data)
if ser.is_valid():
ser.save()
return APIResponse(code=1,msg='注册成功',username=ser.data.get('username'))
else:
return APIResponse(code=0,msg=ser.errors
[序列化类代码(侏罗纪)]
class UserRegisterSerializer(serializers.ModelSerializer):
code=serializers.CharField(max_length=4,min_length=4,write_only=True) # 因为code不是系统的字段所以需要重写序列化给前端
class Meta:
model =models.User
fields=['telephone','code','password']
extra_kwargs={
'password':{'max_length':18,'min_length':8}
}
def validate(self, attrs):
telephone=attrs.get('telephone')
code=attrs.get('code')
if code==cache.get(settings.PHONE_CAHCE_KEY%telephone):
# 验证码通过
if re.match('^1[3-9][0-9]{9}$',telephone):
attrs['username']=telephone # 把手机号设置为默认名字
attrs.pop('code') # 把验证码字段去掉,方便保存
return attrs
else:
raise ValidationError('手机号非法')
else:
raise ValidationError('验证码错误')
# 为了加密密码
def create(self,validated_data):
user=models.User.objects.create_user(**validated_data) # 重写create方法把密码变成密文,视图类中的save方法保存create是明文的
return user
# 4、redis:应用简介
-5大数据类型:
-str、hash(接口缓存,hash可以转换类型因为本身是字典),
-list(分布式):同步调用和异步调用、爬虫一个装地址,一个装信息,实现分布式
-set,zset(去重、排行榜,热搜,销量,音乐排行榜、评论总量、计算)
-redis-server 以某个配置文件启动 启动(windows右键管理服务找到也行)
-redis-cli -h -p
|
|