drf之请求与响应,drf之视图组件,2个视图基类,5个视图扩展类,9个视图子类,视图集,源码分析ViewSetMixin

1.drf之请求与响应

在继承drf中的APIView时

Request

它的请求对象request就不是原来的那个request了(具体去看APIView源码分析),所以没钱请求的request都是一个新的对象,
这时我们便可以通过request.data取出全部数据,而原来的request是取不到request.data的,只能通过请求来看是取request.GET.get(k)或者request.POST.get(k)中的值且取不到put中的数据,
所以drf中的APIView是为了帮我们更好的拿到数据,其他的跟之前用起来一样,因为他们的底层都是继承了一个共同的父类View。
复制代码
Response

 

在源码中有参数data,status,template_name,headers,content_typy(exception不看了)

其中data是将列表字典序列化之后以json的格式返回给前端(放在http响应的body中了)

status  响应状态码

template_name 就是前端模板

content_type 是用来响应前端返回的数据是什么类型的(有json,from/data,url类型)

复制代码

drf能够解析的请求编码,响应编码

能够解析的请求编码和响应编码被放到drf中steeings的文件中了,这是drf的配置文件,我们可以在我们的项目中把其他模块配置文件中的值给写入到我们项目文件的配制文件底下,在这时这个数据就优先用我们配置文件底下的。

复制代码
# drf配置中的源文件
DEFAULTS = { # Base API policies 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ], 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ] }
复制代码

此时DEFAULT_PARSER_CLASSES的valve值就是前端返回给后端的格式只能是什么类型的,在项目的配制文件中加入代码接下来我们把json格式给注掉看下详情。

复制代码
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.TemplateHTMLRenderer',
    ],
    'DEFAULT_PARSER_CLASSES': [
        # 'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ],
}

 


就会出现不让传json格式的数据


复制代码

接下来DEFAULT_RENDERER_CLASSES是前端显示的格式,我们把json格式注掉之后,在postman中就直接返回前端的代码,同样的道理,把rest_framework注掉以后在前端就会返回json格式的数据

复制代码
    'DEFAULT_RENDERER_CLASSES': [
        # 'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.TemplateHTMLRenderer',

 

 

复制代码

我们不仅仅可以在全局的设置里面修改这些配制,我们还可以在局部界面修改这些配置。这些与配置文件中都是一一对应的,一个不写,他就不会显示这种格式

from rest_framework.parsers import  JSONParser,FormParser,MultiPartParser
from rest_framework.renderers import JSONRenderer,TemplateHTMLRenderer


class TestView(APIView):
    parser_classes = [JSONParser, FormParser, MultiPartParser]
class Tes_tView(APIView):
    renderers_classes = [JSONRenderer, TemplateHTMLRenderer]

上述优先级是自己局部页面加的配置,然后自己项目配置中,最后drf配置,这样优先级来执行。

2.drf之视图组件

自己去了解继承,封装和多态

3.两个视图基类

我们五个接口中大部分代码重复,我们就可以用drf中的GenericAPIView给写到一起,然后在分发下去,这就是两个视图基类,可以理解为基于GenericAPIView写接口

复制代码
class BookViews(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers
    def get(self,request):
        book_list = self.get_queryset()
        res =BookSerializers(instance=book_list,many=True)
        return  Response(res.data)

    def post(self,request):
        res = self.get_serializer(data=request.data)
        if res.is_valid():
            res.save()
            return  Response({'code':201,'msg':'添加成功'})
        return Response({'code':201,'msg': res.errors})


class OneBookViews(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers
    def get(self,request,pk):
        book_list = self.get_object()
        res =self.get_serializer(instance=book_list)
        return  Response(res.data)

    def put(self,request,pk):
        book_list = self.get_object()
        res = self.get_serializer(instance=book_list,data=request.data)
        if res.is_valid():
            res.save()
            return  Response({'code':201,'msg':'修改成功'})
        return Response({'code':201,'msg': res.errors})

    def delete(self,request,pk):
        self.get_queryset().filter(pk=pk).delete()
        return Response('')
复制代码

 4.五个视图扩展类

五个视图扩展类我们可以自己用代码来执行,也可以引用drf中的mixins来执行

复制代码
class Get(GenericAPIView,ListModelMixin):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

class Post(GenericAPIView,CreateModelMixin):
    def post(self,request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

class OneGet(GenericAPIView,RetrieveModelMixin):
    def oneget(self,request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)


class Put(GenericAPIView,UpdateModelMixin):
    def put(self,request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

class Delete(GenericAPIView,DestroyModelMixin):
    def delete(self,request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
复制代码

如果不想引用Mixin就可以把两个视图基类拔下来直接放到每个视图扩展类下面就行,下面我们来看ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin。

(1)ListModelMixin源码(get查多个)

复制代码
class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
复制代码

(2)CreateModelMixin源码(post)

复制代码
class CreateModelMixin:
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}
复制代码

(3)RetrieveModelMixin源码 (get查一个)

class RetrieveModelMixin:
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

(4)UpdateModelMixin源码(put)

复制代码
class UpdateModelMixin:
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)
复制代码

(5)DestroyModelMixin源码(delete)

复制代码
class DestroyModelMixin:
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()
复制代码

5.9个视图子类

9个视图子类就是把包含上面的五个视图扩展类以及他们的拼接,自己继承就行

复制代码
class Get(GenericAPIView,ListModelMixin):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

class Post(GenericAPIView,CreateModelMixin):
    def post(self,request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

class OneGet(GenericAPIView,RetrieveModelMixin):
    def oneget(self,request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)


class Put(GenericAPIView,UpdateModelMixin):
    def put(self,request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

class Delete(GenericAPIView,DestroyModelMixin):
    def delete(self,request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)


# 增加,查询
class Get_Post(Get,Post):
    pass


# 修改并查询
class OneGet_Put(OneGet,Put):
    pass
# 删除并查询

class OneGet_Delete(OneGet,Delete):
    pass


# 修改删除查询
class OneGet_Put_Delete(OneGet,Put,Delete):
    pass


# 全部
class All(Get,Post,OneGet,Put,Delete):
    pass
复制代码

6.视图集

我自己写的

复制代码
View.py
class
BookViews(All): queryset = Book.objects.all() serializer_class = BookSerializers def get(self,request,pk): try: int(pk) get = super().oneget(request,pk) except: get = super().get(request) return Response(get.data) def post(self,request,pk): get = super().post(request,pk) return Response(get) def put(self,request,pk): get = super().put(request,pk) return Response(get) def delete(self,request,pk): get = super().delete(request,pk) return Response(get)
复制代码
urls.py
re_path('^books/((?P<pk>[1-9]\d*)/|)', views.BookViews.as_view())

我是匹配到同一个路由上面,接下来我们用一个视图集匹配到两个路由上面,这时我们就需要用到ReadOnlyModelViewSet,此时我们的代码可以精简为

View.py
from
rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet class BookViews(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializers
urls.py
    path('books/', views.BookViews.as_view({'get': 'list', 'post': 'create'})),
    path('books/<int:pk>/', views.BookViews.as_view({'get': 'retrieve', 'put': 'update','delete': 'destroy'})),

7.源码分析ViewSetMixin

复制代码
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
    # 路由中as_view中必须传参数,必须传字典:{'get': 'list', 'post': 'create'}
    if not actions: 
        raise TypeError("The `actions` argument must be provided when "
                        "calling `.as_view()` on a ViewSet. For example "
                        "`.as_view({'get': 'list'})`")
    # 路由匹配成功,执行view(request),request是老的request
    def view(request, *args, **kwargs):
        # actions={'get': 'list', 'post': 'create'}
        for method, action in actions.items():
            # method:get      action:list
            # self 是视图类的对象中通过反射,查找list,
            # handler视图类中的list方法
            handler = getattr(self, action)
            # 向视图类的对象中,反射 method:get,handler:list方法
            # self.get=list
            setattr(self, method, handler)
        return self.dispatch(request, *args, **kwargs)
    return csrf_exempt(view)
复制代码

 

posted @   shangxin_bai  阅读(77)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示