• RESTful规范(二)


    七 解析器

    解析器的作用:

    -用来解析前台传过来的数据编码方式
       urlencoded:form表单:name=lqz&age=18
       formdata :上传文件:--dadfgdgag--   
       json:json格式   {"name":"lqz"}
    -解析器取的顺序
       1 视图类中
       2 django总settings里取
       3 drf默认的配置文件取
    —全局配置
       在setting中: 
          REST_FRAMEWORK = {
             'DEFAULT_PARSER_CLASSES':[
                'rest_framework.parsers.JSONParser',
                # 'rest_framework.parsers.FormParser',
             ]
    
          }
    -局部使用:
       在视图类中:
       from rest_framework.parsers import JSONParser,MultiPartParser,FormParser
       parser_classes = [JSONParser,FormParser]

    例子

    解析器
    局部配置
    from rest_framework.parsers import JSONParser
    class Book(APIView):
        parser_classes = [JSONParser, ]
        def get(self,request,*args,**kwargs):
            return HttpResponse('ok')
        def post(self,request):
            print(request.data)
            return HttpResponse('post')
    
    from rest_framework.parsers import JSONParser,MultiPartParser,FormParser
    class Book(APIView):
        parser_classes = [JSONParser,FormParser]
        def get(self,request,*args,**kwargs):
            return HttpResponse('ok')
        def post(self,request):
            print(request.data)
            return HttpResponse('post')

     八、认证组件

    1、校验是否登陆

        -作用:校验是否登陆
            -首先定义一个类,继承BaseAuthentication,写一个方法:authenticate,在方法内部,实
            证过程,认证通过,返回None或者两个对象(user,auth),这两个对象,在视图类的request中可以取出来
            from rest_framework.authentication import BaseAuthentication
            class myAuthen(BaseAuthentication):
                def authenticate(self, request):
                    token = request.query_params.get('token')
                    ret = models.UserToken.objects.filter(token=token).first()
                    if ret:
                        # return ret.user, ret
                        # 要写多个认证类,这个地返回None
                        # 最后一个认证类,返回这俩值
                        return ret.user, ret
                    else:
                        raise AuthenticationFailed('您没有登陆')
                        
            -局部使用:在视图类中(可以写多个)
                authentication_classes = [myAuthen, ]
            -全局使用:
                 "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
            

    2、正常非drf认证代码,update_or_create意思是有则更新,无则创建

    class User(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    pwd=models.CharField(max_length=32,null=True)
    mychoice=((1,'普通用户'),(2,'超级用户'),(3,'宇宙用户'))
    usertyle=models.IntegerField(choices=mychoice,default=1)

    class UserToken(models.Model):
    user=models.OneToOneField(to=User,to_field='nid')
    token=models.CharField(max_length=64)


    def get_token(username): import hashlib import time md
    = hashlib.md5() # update内必须传bytes格式 md.update(username.encode('utf-8')) md.update(str(time.time()).encode('utf-8')) return md.hexdigest() class Login(APIView): def post(self, request): response = MyResponse() name = request.data.get('name') pwd = request.data.get('pwd') user = models.User.objects.filter(name=name, pwd=pwd).first() if user: response.msg = '登陆成功' # 登陆成功,返回一个随机字符串,以后在发请求,都携带这个字符串 token = get_token(name) response.token = token # 把随机字符串保存到数据库,有就更新,没有就创建 # ret=models.UserToken.objects.update_or_create(user_id=user.id,kwargs={'token':token}) ret = models.UserToken.objects.update_or_create(user=user, defaults={'token': token}) else: response.msg = '用户名或密码错误' response.status = 101 return JsonResponse(response.get_dic)

    3、drf的认证组件用法,return user或者auth

    class myAuthen():
        def authenticate(self,request):
            token = request.query_params.get('token')
            ret = models.UserToken.objects.filter(token=token).first()
            if ret:
                return ret.user,ret
            else:
                raise AuthenticationFailed('您咩有登陆')
    
        def authenticate_header(self,value):
            pass
    
    
    from rest_framework.request import Request
    from app01 import myserial
    
    
    class Book(APIView):
    authentication_classes = [myAuthen, ]
    def get(self, request):
    response = MyResponse()
    print(request.user.name)
    print(request.auth.token)
    # 必须登陆才能访问
    books = models.Book.objects.all()
    ret = myserial.BookSer(instance=books, many=True)
    response.msg = '查询成功'
    response.data = ret.data
    return JsonResponse(response.get_dic, safe=False)

    4、先建个auth.py,存入认证组价的功能

    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    from app01 import models
    
    
    class myAuthen(BaseAuthentication):
        def authenticate(self, request):
            token = request.query_params.get('token')
            ret = models.UserToken.objects.filter(token=token).first()
            if ret:
                # return ret.user, ret
                # 要写多个认证类,这个地返回None
                # 最后一个认证类,返回这俩值
                return ret.user, ret
            else:
                raise AuthenticationFailed('您没有登陆')

    5、若在setting里配置了全局验证,则全局验证,但是视图函数里的login()不需要,则我们参考了顺序是先找局部,在找setting里。所以需要在视图函数里配置

    authentication_classes = [],即不需要验证
    class Login(APIView):
        authentication_classes = []
        def post(self, request):
            response = MyResponse()
            name = request.data.get('name')
            pwd = request.data.get('pwd')
            user = models.User.objects.filter(name=name, pwd=pwd).first()
            if user:
                response.msg = '登陆成功'
                # 登陆成功,返回一个随机字符串,以后在发请求,都携带这个字符串
                token = get_token(name)
                response.token = token
                #     把随机字符串保存到数据库,有就更新,没有就创建
                #     ret=models.UserToken.objects.update_or_create(user_id=user.id,kwargs={'token':token})
                ret = models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
    
            else:
                response.msg = '用户名或密码错误'
                response.status = 101
            return JsonResponse(response.get_dic)

    6、settings

    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser',
            # 'rest_framework.parsers.FormParser',
        ],
        "DEFAULT_AUTHENTICATION_CLASSES": ["app01.auth.myAuthen", ],
    "DEFAULT_PERMISSION_CLASSES":["app01.auth.myPermission",]
    
    }

    7、存的token数据一般存在服务器端数据库里,但是存在压力,第一存在redis里,第二种方式就是不存数据库的token验证,及如下所示

    def get_token(id,salt='123'):
        import hashlib
        md=hashlib.md5()
        md.update(bytes(str(id),encoding='utf-8'))
        md.update(bytes(salt,encoding='utf-8'))
    
        return md.hexdigest()+'|'+str(id)
    
    def check_token(token,salt='123'):
        ll=token.split('|')
        import hashlib
        md=hashlib.md5()
        md.update(bytes(ll[-1],encoding='utf-8'))
        md.update(bytes(salt,encoding='utf-8'))
        if ll[0]==md.hexdigest():
            return True
        else:
            return False
    
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            success=check_token(token)
            if success:
                return
            else:
                raise AuthenticationFailed('认证失败')
        def authenticate_header(self,request):
            pass
    class Login(APIView):
        def post(self,reuquest):
            back_msg={'status':1001,'msg':None}
            try:
                name=reuquest.data.get('name')
                pwd=reuquest.data.get('pwd')
                user=models.User.objects.filter(username=name,password=pwd).first()
                if user:
                    token=get_token(user.pk)
                    # models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                    back_msg['status']='1000'
                    back_msg['msg']='登录成功'
                    back_msg['token']=token
                else:
                    back_msg['msg'] = '用户名或密码错误'
            except Exception as e:
                back_msg['msg']=str(e)
            return Response(back_msg)
    from rest_framework.authentication import BaseAuthentication
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if token_obj:
                return
            else:
                raise AuthenticationFailed('认证失败')
        def authenticate_header(self,request):
            pass
    
    class Course(APIView):
        authentication_classes = [TokenAuth, ]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')

    九 权限组件

    1、校验用户是否有权限访问

    -作用:校验用户是否有权限访问
        -因为是在认证通过才执行,所以可以取出user
        class myPermission():
            message = '不是超超级用户,查看不了'
            def has_permission(self, request, view):
                if request.user.usertyle != 3:
                    return False
                else:
                    return True
        -局部使用
            在视图类中:permission_classes=[myPermission,]
        -全局使用
            在setting中:
            "DEFAULT_PERMISSION_CLASSES":["app01.auth.myPermission",]

    2、choices=的写法,一般用性别等不常用的常识

    class User(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        pwd=models.CharField(max_length=32,null=True)
        mychoice=((1,'普通用户'),(2,'超级用户'),(3,'宇宙用户'))
        usertyle=models.IntegerField(choices=mychoice,default=1)
    
    class UserToken(models.Model):
        user=models.OneToOneField(to=User,to_field='nid')
        token=models.CharField(max_length=64)

    3、eg

    from rest_framework.permissions import BasePermission
    class myPermission(BasePermission):
        message = '不是超超级用户,查看不了'
        def has_permission(self, request, view):
            if request.user.usertyle != 3:
                return False
            else:
                return True


    REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES':[
    'rest_framework.parsers.JSONParser',
    # 'rest_framework.parsers.FormParser',
    ],
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.auth.myAuthen", ],
    "DEFAULT_PERMISSION_CLASSES":["app01.auth.myPermission",]

    }
    from app01.auth import myAuthen
    from app01.auth import myPermission
    
    class Book(APIView):
        # authentication_classes = [myAuthen, ]
        # permission_classes=[myPermission,]
    
        def get(self, request):
            response = MyResponse()
            print(request.user.name)
            print(request.auth.token)
            # 必须登陆才能访问
            books = models.Book.objects.all()
            ret = myserial.BookSer(instance=books, many=True)
            response.msg = '查询成功'
            response.data = ret.data
            return JsonResponse(response.get_dic, safe=False)

    十、频率组件

    1、参考原码写的符合频率组件logic的代码

    class MyThro():
        VISIT_RECORD = {}
        # VISIT_RECORD = {ip:[时间1,时间2],ip2:[],ip3:[当前时间]}
    
        def __init__(self):
            self.history = None
    
        def allow_request(self, request, view):
            # (1)取出访问者ip
            # print(request.META)
            ip = request.META.get('REMOTE_ADDR')
            import time
            ctime = time.time()
            # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
            if ip not in self.VISIT_RECORD:
                self.VISIT_RECORD[ip] = [ctime, ]
                return True
            self.history = self.VISIT_RECORD.get(ip)
            # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
            while self.history and ctime - self.history[-1] > 60:
                self.history.pop()
            # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
            # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
            if len(self.history) < 3:
                self.history.insert(0, ctime)
                return True
            else:
                return False
    
        def wait(self):
            import time
            ctime = time.time()
            return 60 - (ctime - self.history[-1])

    视图函数使用代码

    from app01.auth import MyThro
    class Book(APIView):
        authentication_classes = [myAuthen, ]
        permission_classes=[]
        throttle_classes=[MyThro,]
    
        def get(self, request):
            # request.user
            response = MyResponse()
            # request.GET
            print(request.user.name)
            print(request.auth.token)
            # 必须登陆才能访问
            books = models.Book.objects.all()
            ret = myserial.BookSer(instance=books, many=True)
            response.msg = '查询成功'
            response.data = ret.data
            return JsonResponse(response.get_dic, safe=False)

    2、使用

        频率:
            -定义一个类:
            from rest_framework.throttling import SimpleRateThrottle
            class MyThro(SimpleRateThrottle):
                scope = 'aaa'
                def get_cache_key(self, request, view):
                    # return self.get_ident(request)
                    return request.META.get('REMOTE_ADDR')
                
            -setting中配置
            "DEFAULT_THROTTLE_RATES":{
                'aaa':'3/msssssss'
            }
            
            -全局使用:
                'DEFAULT_THROTTLE_CLASSES':['app01.auth.MyThro',],
            -局部使用:
                throttle_classes=[MyThro,]

    eg.

    from rest_framework.throttling import SimpleRateThrottle
    class MyThro(SimpleRateThrottle):
        scope = 'aaa'
        def get_cache_key(self, request, view):
            # return self.get_ident(request)
            return request.META.get('REMOTE_ADDR')
            # return

    3、假如全局限制每分钟查看3次,视图函数每分钟10次,则需要在

    "DEFAULT_THROTTLE_RATES":{
    'aaa':'3/msssssss'
    },
    
    
    from rest_framework.throttling import SimpleRateThrottle
    class MyThro(SimpleRateThrottle):
    scope = 'aaa'
    def get_cache_key(self, request, view):
    # return self.get_ident(request)
    return request.META.get('REMOTE_ADDR')
    # return

    将aaa 赋值为10/mmmmms

  • 相关阅读:
    【2019.8.14 慈溪模拟赛 T1】我不是!我没有!别瞎说啊!(notme)(BFS+DP)
    【2019.8.8 慈溪模拟赛 T2】query(query)(分治+分类讨论)
    【CometOJ】Comet OJ
    【CodeForces】CodeForcesRound576 Div1 解题报告
    【2019.8.12 慈溪模拟赛 T2】汪哥图(wang)(前缀和)
    【2019.8.12 慈溪模拟赛 T1】钥匙(key)(暴力DP)
    【2019.8.9 慈溪模拟赛 T2】摘Galo(b)(树上背包)
    【BZOJ3171】[TJOI2013] 循环格(网络流)
    【AtCoder】AtCoder Grand Contest 035 解题报告
    【2019.8.11上午 慈溪模拟赛 T2】十七公斤重的文明(seventeen)(奇偶性讨论+动态规划)
  • 原文地址:https://www.cnblogs.com/di2wu/p/10141118.html
Copyright © 2020-2023  润新知