zoukankan      html  css  js  c++  java
  • Django之restframework2视图三部曲

    视图三部曲

    下面我来来看restframework是如何将冗余的代码一步步的进行封装.

    这里主要用到的是多继承

    
    
    

    第一步mixin类编写视图

    AuthorModelSerializer:
    class AuthorModelSerializer(serializers.ModelSerializer):
        class Meta:
            model=models.Author
            fields='__all__'
    from rest_framework import mixins,generics
    class Authors(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer
    
        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 AuthorsDetailView(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,generics.GenericAPIView):
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer
        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.delete(request,*args,**kwargs)

    第二部使用通用的基于类的视图

    from rest_framework import generics
    
    class Authors(generics.ListCreateAPIView):
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer
    
    
    class AuthorsDetailView(generics.RetrieveUpdateDestroyAPIView):
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerialize
    
    
    # class ListCreateAPIView(mixins.ListModelMixin,
    #                         mixins.CreateModelMixin,
    #                         GenericAPIView):
    # class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
    #                                    mixins.UpdateModelMixin,
    #                                    mixins.DestroyModelMixin,
    #                                    GenericAPIView):

    通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py模块。

    到这里是第二部,但是我们还是需要实例化两个类来对应两个url,为什么要实例两个类,因为每个类都有get方法,

    如果不写两个类,怎么知道走哪个get方法?

    第三部viewsets.ModelViewSet

    url部分

    path('authors/', views.AuthorModelView.as_view({'get':'list','post':'create'}),name='authors'),
    re_path(r'^authors/(?P<pk>d+)/$', views.AuthorModelView.as_view({'get':'retrieve',
                                                                       'put':'update',
                                                                        'delete':'destroy'}),name='authors_detail'),
    ##############流程########
    from rest_framework import viewsets
    class AuthorModelView(viewsets.ModelViewSet):
    ModelViewSet--->GenericViewSet--->ViewSetMixin----在这个类下执行了as_view
    for method, action in actions.items():
      #as_view后面的参数倍循环后得到了请求key,相对应的方法values
        handler = getattr(self, action) # handler -->getattr(self,list) self--->自己写的类AuthorModelView
        setattr(self, method, handler)   #setattr(self,get,self.list) self.get---->执行self.list

    view:

    from rest_framework import viewsets
    class AuthorModelView(viewsets.ModelViewSet):
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer

    认证组件

    局部视图认证:

    在app01.authented.py:

    from rest_framework.authentication import BaseAuthentication
    from app01 import models
    from rest_framework.exceptions import AuthenticationFailed
    
    class AuthentiCate(BaseAuthentication):
    
        def authenticate(self, request):
            token=request.GET.get('token')
            token_obj=models.Token.objects.filter(token=token).first()
    
            if not token_obj:
                raise AuthenticationFailed('认证失败')
            return token_obj.user.username,token_obj

    在views.py:

    def get_random_str(user):
        import hashlib,time
        ctime=str(time.time())
    
        md5=hashlib.md5(bytes(user,encoding="utf8"))
        md5.update(bytes(ctime,encoding="utf8"))
    
        return md5.hexdigest()
    
    from app01.authented import AuthentiCate
    
    from rest_framework import viewsets
    class AuthorModelView(viewsets.ModelViewSet):
        ##*******************###
        authentication_classes = [AuthentiCate]
        ##*******************###
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer
    
    
    class LoginView(APIView):
    
        def post(self,request):
            ret={'status_code':1000,'msg':None}
            try:
                username=request.data.get('username')
                pwd=request.data.get('pwd')
    
                user=models.User.objects.filter(username=username,pwd=pwd).first()
                if user:
                    radom_str=get_random_str(user.username)
                    models.Token.objects.update_or_create(user=user,defaults={'token':radom_str})
                    ret['token']=radom_str
                else:
                    ret['status_code']=1001
                    ret['msg']='用户名密码错误'
            except Exception as e:
                res["code"] = 1002
                res["msg"] = e
    
            return Response(data=ret)

    全局视图认证组件:

    在settings的配置:

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.authented.AuthentiCate",]
    }

    权限组件

    局部权限组件:

    在app01.service.permissions.py中:

    from rest_framework.permissions import BasePermission
    class SVIPPermission(BasePermission):
        message="SVIP才能访问!"
        def has_permission(self, request, view):
            if request.user.user_type==3:
                return True
            return False

    views:

    from app01.service.permissions import *
    
    class BookViewSet(generics.ListCreateAPIView):
        permission_classes = [SVIPPermission,]
        queryset = Book.objects.all()
        serializer_class = BookSerializers

    全局视图权限

    settings.py配置如下:

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
    }

    如果想添加白名单,在该类下加上permission_classes =[ ]源码找的时候就会先找这里

    throttle(访问频率)组件

    局部视图throttle:

    在app01.service.throttles.py中:

    from rest_framework.throttling import BaseThrottle
    
    VISIT_RECORD={}
    class VisitThrottle(BaseThrottle):
    
        def __init__(self):
            self.history=None
    
        def allow_request(self,request,view):
            remote_addr = request.META.get('REMOTE_ADDR')
            print(remote_addr)
            import time
            ctime=time.time()
    
            if remote_addr not in VISIT_RECORD:
                VISIT_RECORD[remote_addr]=[ctime,]
                return True
    
            history=VISIT_RECORD.get(remote_addr)
            self.history=history
    
            while history and history[-1]<ctime-60:
                history.pop()
    
            if len(history)<3:
                history.insert(0,ctime)
                return True
            else:
                return False
    
        def wait(self):
            import time
            ctime=time.time()
            return 60-(ctime-self.history[-1])

    在views.py中:

    from app01.service.throttles import *
    
    class BookViewSet(generics.ListCreateAPIView):
        throttle_classes = [VisitThrottle,]
        queryset = Book.objects.all()
        serializer_class = BookSerializers

    全局视图的throttle

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
        "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
    }

    内置的throttle类

    class VisitThrottle(SimpleRateThrottle):
    
        scope="visit_rate"
        def get_cache_key(self, request, view):
    
            return self.get_ident(request)

    settings.py设置:

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
        "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
        "DEFAULT_THROTTLE_RATES":{
            "visit_rate":"5/m",
        }
    }

    解析器

    from rest_framework.parsers import JSONParser,FormParser
    class PublishViewSet(generics.ListCreateAPIView):
    ########################
        parser_classes = [FormParser,JSONParser]
    ############################
        queryset = Publish.objects.all()
        serializer_class = PublshSerializers
        def post(self, request, *args, **kwargs):
            print("request.data",request.data)
            return self.create(request, *args, **kwargs)

    全局:

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
        "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
        "DEFAULT_THROTTLE_RATES":{
            "visit_rate":"5/m",
        },
        "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',]
    }

    URL的编写

    from django.conf.urls import url, include
    from rest_framework import routers
    from tutorial.quickstart import views
    
    router = routers.DefaultRouter()
    router.register(r'authors', views.AuthorsViewSet)
    
    
    urlpatterns = [
        url(r'^', include(router.urls)),

    只要注册了router.register,就会有相对应的

    path('authors/',views.AuthorModelView.as_view({'get':'list','post':'create'}),name='authors'),
    re_path(r'^authors/(?P<pk>d+)/$',views.AuthorModelView.as_view({'get':'retrieve','put':'update','delete':'destroy'}),name='authors_detail'),

    并且还相应的增加了其他两条restframework的测试url

    分页

    分页之自定义:

    第一版:

    from rest_framework.pagination import PageNumberPagination
    class Mypagination(PageNumberPagination):
            page_size = 1
            page_query_param = 'page'
            page_size_query_param = "size"
            max_page_size = 5
        
    class BookView(APIView):
        # authentication_classes = [TokenAuth,] # [TokenAuth(),]
        # permission_classes = []
        # throttle_classes = []
    
        def get(self,request):
            book_list=Book.objects.all()
    
            # 分页
    
            pnp=Mypagination()
            books_page=pnp.paginate_queryset(book_list,request,self)
    
            bs=BookModelSerializers(books_page,many=True,context={'request': request})
            return Response(bs.data)

    分页之最终版:

    from rest_framework.pagination import PageNumberPagination
    class Mypagination(PageNumberPagination):
            page_size = 1
            page_query_param = 'page'
            page_size_query_param = "size"
            max_page_size = 5
    
    from rest_framework import viewsets
    class AuthorModelView(viewsets.ModelViewSet):
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer
        pagination_class = Mypagination

    偏移分页

    from rest_framework.pagination import LimitOffsetPagination

    版本的设置

    1.设置settings:

    REST_FRAMEWORK={
     'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',#路由配置版本
        'DEFAULT_VERSION':'v1', #默认的版本
        'ALLOWED_VERSIONS':['v1','v2'], #允许的版本
        'VERSION_PARAM':'version', # 版本参数

    2.设置路由:
    分发的时候设置:

    urlpatterns = [
        path('admin/', admin.site.urls),
        re_path(r'^api/(?P<version>w+)/', include('api.urls')),
    ]

    3.获取版本:

        request.version #获取版本

     跨域请求CORS

    CORS:
    解决跨域的时候是加上特殊的响应头
    jsonp跨域只能是get请求,
    cors可以发送post和get请求.
    
    配置中间件
    from django.utils.deprecation import MiddlewareMixin
    class CORSMiddleware(MiddlewareMixin):
        def process_response(self,request,response):
            #添加响应头
            # 允许你的域名来获取我的数据
            # 允许所有的域名来获取数据
            response['Access-Control-Allow-Origin']='*'
    
            # 允许你携带Content-Type请求头 如果要多的用逗号,隔开
            response['Access-Control-Allow-Headers']='Content-Type'
    
            # 允许你发送DELETE,和PUT
            response['Access-Control-Allow-Methods']='DELETE,PUT'
    
            return response
    #setting里配置
    MIDDLEWARE = [
    'api.cors.CORSMiddleware',
    ]

    restful规范 猛击!

  • 相关阅读:
    使用迭代器模式批量获得数据(C#实现)
    如何从技术上预防抢票软件刷屏
    如何用Tesseract做日文OCR(c#实现)
    我的.net开发百宝箱
    程序员必备基础:Git 命令全方位学习
    Java 异常处理的十个建议
    50道Java集合经典面试题(收藏版)
    记一次接口性能优化实践总结:优化接口性能的八个建议
    100道MySQL数据库经典面试题解析(收藏版)
    800+Java后端经典面试题,希望你找到自己理想的Offer呀~
  • 原文地址:https://www.cnblogs.com/chenxuming/p/9343363.html
Copyright © 2011-2022 走看看