ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

rest_framework 之视图三部曲

2020-06-06 14:08:39  阅读:204  来源: 互联网

标签:return self args request rest framework 视图 kwargs class


一、视图三部曲

1  使用混合(mixins)

上一节的视图部分:

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from django.shortcuts import HttpResponse
from django.core import serializers


from rest_framework import serializers


class BookSerializers(serializers.ModelSerializer):
      class Meta:
          model=Book
          fields="__all__"
          #depth=1


class PublshSerializers(serializers.ModelSerializer):

      class Meta:
          model=Publish
          fields="__all__"
          depth=1


class BookViewSet(APIView):

    def get(self,request,*args,**kwargs):
        book_list=Book.objects.all()
        bs=BookSerializers(book_list,many=True,context={'request': request})
        return Response(bs.data)


    def post(self,request,*args,**kwargs):
        print(request.data)
        bs=BookSerializers(data=request.data,many=False)
        if bs.is_valid():
            print(bs.validated_data)
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)


class BookDetailViewSet(APIView):

    def get(self,request,pk):
        book_obj=Book.objects.filter(pk=pk).first()
        bs=BookSerializers(book_obj,context={'request': request})
        return Response(bs.data)

    def put(self,request,pk):
        book_obj=Book.objects.filter(pk=pk).first()
        bs=BookSerializers(book_obj,data=request.data,context={'request': request})
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)


class PublishViewSet(APIView):

    def get(self,request,*args,**kwargs):
        publish_list=Publish.objects.all()
        bs=PublshSerializers(publish_list,many=True,context={'request': request})
        return Response(bs.data)


    def post(self,request,*args,**kwargs):

        bs=PublshSerializers(data=request.data,many=False)
        if bs.is_valid():
            # print(bs.validated_data)
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)


class PublishDetailViewSet(APIView):

    def get(self,request,pk):

        publish_obj=Publish.objects.filter(pk=pk).first()
        bs=PublshSerializers(publish_obj,context={'request': request})
        return Response(bs.data)

    def put(self,request,pk):
        publish_obj=Publish.objects.filter(pk=pk).first()
        bs=PublshSerializers(publish_obj,data=request.data,context={'request': request})
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)

 mixin类编写视图 :封装逻辑

urls.py

 url(r'^books/$', views.BookView.as_view(),name="books"),#
 url(r'^books/(\d+)/$', views.BookDetailView.as_view(),name="detailbook"),#

(1)查看 

from rest_framework import mixins
from rest_framework import generics
#
class BookViewSet(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView): #GenericAPIView继承了APIView,APIView继承了View,用户访问时相当于执行View方法->执行dispatch方法
->执行get方法->相当于执行list方法 queryset = Book.objects.all() #不能改这两个变量的名字 serializer_class = BookSerializers# def get(self, request, *args, **kwargs): #整个获取数据的逻辑被封装到ListModelMixin这个类下的List方法中,                             以后再有关于所有获取数据的逻辑都从这个类下取 return self.list(request, *args, **kwargs) #list->get->dispatch->View# 
查看mixins.ListModelMixin源码
class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset()) #get_queryset方法封装在GenericAPView类中,拿到了queryset数据,
            这里的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)
查看generics.GenericAPIView源码
#
class GenericAPIView(views.APIView):#

    queryset = None
    serializer_class = None

    lookup_field = 'pk'
    lookup_url_kwarg = None

    # The filter backend classes to use for queryset filtering
    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

    # The style to use for queryset pagination.
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

    def get_queryset(self):   #

        assert self.queryset is not None, (
            "'%s' should either include a `queryset` attribute, "
            "or override the `get_queryset()` method."
            % self.__class__.__name__
        )
        #
        queryset = self.queryset  #从自己当前类(上面是BookViewSet)找queryset,拿到数据交给queryset
        if isinstance(queryset, QuerySet):  #
            # Ensure queryset is re-evaluated on each request.
            queryset = queryset.all()  #
        return queryset

(2)添加

class BookViewSet(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):

    queryset = Book.objects.all()
    serializer_class = BookSerializersdef post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
 查看mixins.CreateModelMixin源码
#
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) #相当于save操作
        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)单条数据的get请求

class BookDetailViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Book.objects.all()  #
    serializer_class = BookSerializers#
#
    def get(self, request, *args, **kwargs):#
        return self.retrieve(request, *args, **kwargs)#

查看mixins.RetrieveModelMixin源码

#
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)单条数据的delete请求

class BookDetailViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

    def delete(self, request, *args, **kwargs): #
        return self.destroy(request, *args, **kwargs)#

查看mixins.DestroyModelMixin源码

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()#

(4)单条数据的put请求

class BookDetailViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

    def put(self, request, *args, **kwargs):#
        return self.update(request, *args, **kwargs)#

查看mixins.UpdateModelMixin源码

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)#save操作,本质上是一个更新操作

        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)#

 以上这种方式代码量和之前相比没少多少,但主要逻辑都帮我们封装起来了

 2 使用通用的基于类的视图

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

from rest_framework import generics

class BookView(generics.ListCreateAPIView): #
    queryset=Author.objects.all()#
    serializer_class =AuthorModelSerializers#
    
    
#generics.py
class ListCreateAPIView(mixins.ListModelMixin, #
                        mixins.CreateModelMixin,#
                        GenericAPIView):
    """
    Concrete view for listing a queryset or creating a model instance.
    """
    def get(self, request, *args, **kwargs):#
        return self.list(request, *args, **kwargs)#

    def post(self, request, *args, **kwargs):#
        return self.create(request, *args, **kwargs)#

单条数据的查看、更新和删除

from rest_framework import generics

class BookDetailView(generics.RetrieveUpdateDestroyAPIView):#
    queryset = Author.objects.all()#
    serializer_class = AuthorModelSerializers#
#generics.py class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,# mixins.UpdateModelMixin,# mixins.DestroyModelMixin,# GenericAPIView):# """ Concrete view for retrieving, updating or deleting a model instance. """ 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 patch(self, request, *args, **kwargs):#put和patch都是更新 return self.partial_update(request, *args, **kwargs)# def delete(self, request, *args, **kwargs):# return self.destroy(request, *args, **kwargs)#

3 viewsets.ModelViewSet:

统一了上面两个视图类,主要在url这里做了文章

之前的as_view没有传参数,用户访问时找到的as_view是APIView(View)类下面没有处理参数的as_view方法

现在我们把url进行以下设置:

urls.py

   #en
   url(r'^books/$', views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"),
    url(r'^books/(?P<pk>\d+)$', views.BookViewSet.as_view({
                'get': 'retrieve',#
                'put': 'update',#
                'patch': 'partial_update',#
                'delete': 'destroy'#
            }),name="book_detail"),#

上面的url中的as_view传了参数:通过一个字典,传入参数,指定什么请求方式用哪一个内部方法来执行

views.py

#
from rest_framework import viewsets

#只需一个类就能实现get、post、put、patch、delete请求
class BookViewSet(viewsets.ModelViewSet):#
    queryset = Book.objects.all()#
    serializer_class = BookSerializers#

当用户通过get/post请求访问了books之后: -> views.BookViewSet.as_view

现在我们来找as_view方法  BookViewSet->ModelViewSet->GenericViewSet->ViewSetMixin 

class ViewSetMixin:#         (1)
    """
    This is the magic.

    Overrides `.as_view()` so that it takes an `actions` keyword that performs
    the binding of HTTP methods to actions on the Resource.

    For example, to create a concrete view binding the 'GET' and 'POST' methods
    to the 'list' and 'create' actions...

    view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
    """

    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):#actions就是我们传的那个字典 {"get":"list","post":"create"}       (2)

        def view(request, *args, **kwargs): #覆盖了View类下的view方法  (4)
            self = cls(**initkwargs)#
            self.action_map = actions #actions就是我们传的那个字典  {"get":"list","post":"create"}

            for method, action in actions.items(): #method是请求方式,action是实例方法
                handler = getattr(self, action)  #反射找实例方法  self.list   self.create
                setattr(self, method, handler)  #为请求方式设置对应的实例方法

                # setattr(self,"get",self.list)  #这两步相当于:self.get=self.list  self.list =self.create
                # setattr(self,"post",self.create)

            #……
            # And continue as usual
            return self.dispatch(request, *args, **kwargs)#  (5)
            #查找dispatch:->BookViewSet->ModelViewSet-> GenericViewSet->ViewSetMixin->
            # GenericAPIView(views.APIView)->APIView最后找到了APIView下面的dispatch方法
    #……     return csrf_exempt(view) #返回的是当前ViewSetMixins类下的view方法 (3)

#rest_framework\view.py class APIView(View):# #…… def dispatch(self, request, *args, **kwargs): (6) #…… try: self.initial(request, *args, **kwargs)# # Get the appropriate handler method if request.method.lower() in self.http_method_names:# handler = getattr(self, request.method.lower(), #handler就是list、create方法 self.http_method_not_allowed)# else: handler = self.http_method_not_allowed# response = handler(request, *args, **kwargs) #返回的就是list、create方法 (8) #如果get请求走的就是ListModelMixin类下的list方法 #如果post请求走的就是CreateModelMixin类的create方法 #最后执行上述方法后把返回值传给用户 #返回值执行过程:response->dispatch->ViewSetMixin类下的view-> views.BookViewSet.as_view return self.response# (7) 

 

标签:return,self,args,request,rest,framework,视图,kwargs,class
来源: https://www.cnblogs.com/zh-xiaoyuan/p/13040923.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有