zoukankan      html  css  js  c++  java
  • rest_framework视图和组件

    一、视图

    1.基本视图

    #基本视图
    #抽取基类
    from rest_framework.response import Response
    from rest_framework.views import APIView
    from app1.models import *
    from app1.Myserializer import BookSerializer
    from app1.Myserializer import PublishSerializer
    class List():
        def list(self,request,*args,**kwargs):
            response = {'status':100,'msg':'查询成功'}
            g = self.model
            g_ser = self.model_ser(instance=g,many=True)
            response['data'] = g_ser.data
            return Response(response)
    
    class Create():
        def create(self,request,*args,**kwargs):
            response = {'status': 100, 'msg': '新增成功'}
            try:
                p_ser = self.model_ser(data=request.data)
                if p_ser.is_valid():
                    p_ser.save()
                    response['data'] = p_ser.data
                else:
                    response['msg'] = p_ser.errors
            except Exception as e:
                response['msg'] = str(e)
            return Response(response)
    
    #图书查询,新增
    class BooksView(List,Create,APIView):
        model = Book.objects.all()
        model_ser = BookSerializer
        def get(self,request,*args,**kwargs):
            return self.list(request,*args,**kwargs)
    
        def post(self,request,*args,**kwargs):
            return self.create(request,*args,**kwargs)
    
    #出版社查询,新增
    class PublishView(List,Create,APIView):
        model = Publish.objects.all()
        model_ser = PublishSerializer
        def get(self,request,*args,**kwargs):
            return self.list(request,*args,**kwargs)
    
        def post(self,request,*args,**kwargs):
            return self.create(request,*args,**kwargs)

    2.mixin类和generice类编写视图

    from app1.models import *
    from app1.Myserializer import BookSerializer
    from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
    from rest_framework.generics import GenericAPIView
    #ListModelMixin:获取所有 CreateModelMixin:新增 RetrieveModelMixin:获取单本 UpdateModelMixin:更新 DestroyModelMixin:删除
    class BooksView(ListModelMixin,CreateModelMixin,GenericAPIView):
        serializer_class = BookSerializer
        queryset = Book.objects.all()
        #获取所有图书
        def get(self,request,*args,**kwargs):
            return self.list(request,*args,**kwargs)
    
        #新增图书
        def post(self,request,*args,**kwargs):
            return self.create(request,*args,**kwargs)
    
    class BookView(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView):
        serializer_class = BookSerializer
        queryset = Book.objects.all()
    
        #获取单本
        def get(self,request,*args,**kwargs):
            return self.retrieve(request,*args,**kwargs)
    
        #更新图书
        def put(self, request, *args, **kwargs):
            return self.update(request,*args,**kwargs)
    
        #删除图书
        def delete(self,request,*args,**kwargs):
            return self.destroy(request,*args,**kwargs)

    3.使用generics 下ListCreateAPIView,RetrieveUpdateDestroyAPIView

    from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
    #获取所有和新增图书
    class BooksView(ListCreateAPIView):
        serializer_class = BookSerializer
        queryset = Book.objects.all()
    
    #查询单个图书,更新,删除
    class BookView(RetrieveUpdateDestroyAPIView):
        serializer_class = BookSerializer
        queryset = Book.objects.all()

    4.使用ModelViewSet,将两个视图类写成一个类,五种请求:get,get,post,delete

    from app1.models import *
    from app1.Myserializer import BookSerializer
    from rest_framework.viewsets import ModelViewSet
    class BooksView(ModelViewSet):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
    #路由层路由配置
    url(r'^books/$', views.BooksView.as_view({'get':'list','post':'create'})),
    url(r'^books/(?P<pk>d+)$',
        views.BooksView.as_view({'get':'retrieve','put':'update','delete':'destroy'})), 

    5.ViewSetMixin的使用,重写了as_view方法

    要用ViewSetMixin,路由跟之前写法不一样了
    url(r'^test', views.Publish.as_view({'get':'aa'})),
    
    视图类中
    from rest_framework.viewsets import ViewSetMixin
    class Publish(ViewSetMixin,APIView):
        def aa(self,request):
            return HttpResponse('aa')

    二、认证组件

    -什么是认证?是用来干什么的?
      校验用户是否是我的登录用户
    
    -drf源码中找,认证如何实现的
    -APIView的dispach方法---》self.initial(request, *args, **kwargs)----》400行self.perform_authentication(request)---》APIView的perform_authentication(request)----》request.user(request是新的request)---->去Request类中找user,执行--->self._authenticate()(self是新的reqeust对象)---->Request类的_authenticate(self)方法

    使用认证功能

    '''
    1.①写一个认证类MyAuthentication,继承BaseAuthentication
    ②类的内部重写authenticate方法
    ③在authenticate方法中写认证逻辑,认证通过,返回None,认证不通过,抛异常
    ④校验通过,也可以返回当前登录的用户和auth,这样操作,在视图类中,可以通过request.user,获取到当前登录的用户
    ⑤一旦返回了值,后续的认证类就不会再走了
    '''
    
    '''
    2.authentication_classes查找顺序(认证类的查找顺序): 
      ①先在自己类当中找:authentication_classes=[MyAuthentication]
      ②如果自己当中没有配置,去去项目settings.py中去找
      ③如果项目setting中没有配置,去drf的setting中找
    '''
    
    '''
    3.最终在认证中的使用
        局部使用:
            -在视图类中配置:authentication_classes=[MyAuthentication]
        全局使用:
            -在setting.py中配置:
            REST_FRAMEWORK={
            'DEFAULT_AUTHENTICATION_CLASSES':['app1.MyAuth.MyAuthentication']
            }
        全局使用了局部禁用:
            -在视图类中配置:authentication_classes=[]
    '''
    
    from rest_framework.response import Response
    from app1.models import *
    from rest_framework.views import APIView
    import uuid
    from rest_framework.exceptions import AuthenticationFailed
    from rest_framework.authentication import BaseAuthentication
    
    class MyAuthentication(BaseAuthentication):
        def authenticate(self,request):
            #认证相关的东西
            #校验请求是否携带正确的token
            #取出token
            token = request.GET.get('token')
            #校验该次请求是否携带正确的token
            ret = UserToken.objects.filter(token=token).first()
            if ret:
                #正常通过认证的用户
                return ret.user,ret
            else:
                #没有登录或非法用户
                raise AuthenticationFailed('您没有通过认证')
    
    class BooksView(APIView):
        #某个视图类需要登陆后才能查看,只需要在视图类加入下面代码
        authentication_classes=[MyAuthentication]
        def get(self,request):
            return Response('ok')
    
    
    
    class Login(APIView):
        def post(self,request):
            response={'status':100,'msg':None}
            name = request.data.get('name')
            pwd = request.data.get('pwd')
    
            #去数据库校验数据是否存在
            user = User.objects.filter(name=name,pwd=pwd).first()
            if user:
                #正常用户登录成功
    
                #返回唯一的随机字符串
                token = uuid.uuid4()
    
                #生成随机的字符串存到数据库中,如果存在更新token,不存在新增一条
                # 根据user去查询,如果查到数据,更新defaults中的数据,如果查不到,新增一条数据
                ret = UserToken.objects.update_or_create(user=user,defaults={'token':token})
                response['msg'] = '登录成功'
                response['token'] = token
            else:
                response['status'] = 101
                response['msg'] = '账号或密码错误'
            return Response(response)
        
    #请求 
    #http://127.0.0.1:8000/books/?token=735061c3-733d-463d-8158-ccfa2e13f539 
    #token匹配成功就会得到图书信息,否则返回没有通过认证
    
    #加了 authentication_classes=[MyAuthentication] 这句代码,直接访问http://127.0.0.1:8000/books/ 会返回没有通过认证

    三、权限组件

    '''
    权限是什么?
        比如只有超级用户可以访问books这个接口
    使用:
        ①写一个权限类MyPermissions,继承BasePermission
        ②类的内部重写has_permission方法
        ③在has_permission方法内部写权限逻辑,通过返回True,失败返回False
    '''
    user表
    class User(models.Model):
        name=models.CharField(max_length=32)
        pwd=models.CharField(max_length=32)
        choice=((1,'超级用户'),(2,'普通用户'),(3,'穷逼用户'))
        type = models.IntegerField(choices=choice,null=True)
    
    from rest_framework.permissions import BasePermission
    class MyPermissions(BasePermission):
        def has_permission(self, request, view):
            #是否为超级用户
            if request.user.type == 1:
                #如何取type对应的文字 get_字段名_display()
                user_type = request.user.get_type_display()
                #超级用户校验通过返回True
                return True
            else:
                #校验失败返回False
                return False
            
    '''
    最终的使用
    局部使用:
        -在视图类中配置:permission_classes=[MyPermissions]
    全局使用:
        -在settings.py中配置:
        REST_FRAMEWORK={
        'DEFAULT_PERMISSION_CLASSES':['app1.MyAuth.MyPermissions']
        }
    全局使用了局部禁用:
        -在视图类中配置:permission_classes=[]

    四、频率组件

    '''
    频率是什么?
     -同一段时间内,只能访问多少次
    '''
    频率组件的使用:
    ①写一个频率类Mythrottling,继承SimpleRetaThrottle
    ②重写get_cache_key方法,方法返回什么,频率组件就以什么做限制(比如返回ip,就以ip做限制.返回user_id,就会以用户id做限制)
    from rest_framework.throttling import SimpleRateThrottle
    class MyThrottling(SimpleRateThrottle):
        scope = 'xxx'
        def get_cache_key(self, request, view):
            return request.META.get('REMOTE_ADDR')  #返回客户端ip地址
    
    ③在setings.py中配置:
        'DEFAULT_THROTTLE_CLASSES':{
            'xxx:'3/m' #每分钟三次
        }
    
    ④局部使用:
        -在视图类中配置:throttle_classes=[MyThrottling]
     全局使用:
        -在settings.py中配置
        REST_FRAMEWORK={
        'DEFAULT_THROTTLE_CLASSES':['app1.MyAuth.MyThrottling']
        }
    全局使用了局部禁用:
        -在视图类中配置:throttle_classes=[]

    自定义频率控制类

    '''
    频率控制的逻辑
    某个ip地址一分钟只能访问三次
    {ip地址1:[第三次访问的时间,第二次访问的时间,第一次访问的时间],ip地址2:[]}
    (1)取出访问者ip
    (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
    (3)循环判断当前ip的时间列表,有值,并且当前时间减去列表的最后一个时间大于60s,把列表中最后一个数用pop去掉,这样列表中只有60s以内的访问时间,
    (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
    (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
    '''
    from rest_framework.throttling import BaseThrottle
    class MyThrottling(BaseThrottle):
        #访问者ip字典
        VISIT_RECORD = {}
        def __init__(self):
            #访问者ip对应的时间列表
            self.history=None
        def allow_request(self, request, view):
            #(1)取出访问者ip
            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.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])
  • 相关阅读:
    Ubuntu18.04下更改apt源为阿里云源
    sudo: pip:command not found问题解决
    CentOS8 中文输入法
    PyCharm2019 激活方式
    正则爬取京东商品信息并打包成.exe可执行程序
    学习springcloud bus+springcloud config实现刷新配置
    使用springcloud-config统一管理配置文件
    记录一下今天使用maven构建项目分多个模块时遇到的扫描properties问题
    spring+mybatis+thymeleaf
    回调地狱问题
  • 原文地址:https://www.cnblogs.com/lizeqian1994/p/10689839.html
Copyright © 2011-2022 走看看