drf视图组件(5星)

视图组件(5星)

APIView

rest_framework.views.APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

支持定义的类属性

  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类

APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

举例:

from rest_framework.views import APIView
from rest_framework.response import Response

# url(r'^students/$', views.StudentsAPIView.as_view()),
class StudentsAPIView(APIView):
    def get(self, request):
        data_list = Student.objects.all()
        serializer = StudentModelSerializer(instance=data_list, many=True)
        return Response(serializer.data)

GenericAPIView[通用视图类]

from rest_framework.generics import GenericAPIView

继承自APIVIew主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。

提供的关于数据库查询的属性与方法

  • 属性:

    • queryset : 指明使用的数据查询集
  • 方法:

    • get_queryset(self)

      返回视图使用的查询集, 主要是用来提供给Mixin扩展类使用, 是列表视图与详情视图获取数据的基础,默认返回queryset属性, 可以重写, eg:

    from rest_framework.decorators import action
    class TestAPIView(GenericViewSet):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
        # 这里重写这个方法就可以达到一个方法根据请求地址的不同可以返回不同的数据
        def get_queryset(self):
            if self.action == 'login':
                return self.queryset  # login地址访问就返回书的数据
            return Publish.objects.all()  # 其他地址访问就返回Publish的数据
    
        def login(self, request):
            obj = self.get_queryset()  # 获取的是书的queryset对象
    
        def register(self, request):
            obj = self.get_queryset()  # 获取的是出版社的queryset对象
    
    • get_object(self)

      返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用

      在视图中可以调用该方法获取详情信息的模型类对象

      若详情访问的模型类对象不存在,会返回404

      该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。

      eg:

      # url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
      class BookDetailView(GenericAPIView):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
      
          def get(self, request, pk):
              book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象
              serializer = self.get_serializer(book)
              return Response(serializer.data)
      

提供的关于序列化器使用的属性与方法

  • 属性:

    • serializer_class 指明视图使用的序列化器
  • 方法:

    • get_serializer_class(self)

      当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。

      返回序列化器类,默认返回serializer_class,可以重写,例如:

      class TestAPIView(GenericViewSet):
          queryset = Book.objects.all()
          serializer_class = BookSerializer
          # 这里重写这个方法就可以达到一个方法根据请求地址的不同可以返回不同的序列化器
          def get_serializer_class(self):
              if self.action == 'login':
                  return BookSerializer  # login地址访问就返回书的序列化器
              return PublishSerializer   # 其他地址访问就返回出版社的序列化器
      
          def login(self, request):
              serializer = self.get_serializer_class()  # 获取的是书的序列化器
      
          def register(self, request):
              serializer = self.get_serializer_class()  # 获取的是出版社的序列化器
      

    **get_serializer(self, args, kwargs)

    返回序列化器对象, 主要用来提供给Mixin扩展类使用, 如果我们在视图中想要获取序列化器对象,也可以直接调用此方法

    注意, 该方法在提供序列化器对象的时候, 会向序列化器对象的context属性补充三个数据:request、format、view, 这三个数据对象可以在定义序列化器的时候使用

    • request 当前视图的请求对象
    • view 当前请求的视图类对象
    • format 当前请求期望返回的数据格式

其他可以设置的属性

  • pagination_class 指明分页控制类
  • filter_backends 指明过滤控制后端

使用

from rest_framework.response import Response
from .serializer import BookModelSerializer
from rest_framework.generics import GenericAPIView

class BookAPIView(GenericAPIView):
    queryset = Books.objects.all()  
    serializer_class = BookModelSerializer
  ### 这样以后再写其他接口就只需要再重写上面两行就行了 ###

    # 查所有
    def get(self, request, *args, **kwargs):
        # 获得所有要序列化的对象
        obj_list = self.get_queryset()
        # 序列化
        ser = self.get_serializer(obj_list, many=True)
        return Response(ser.data)

    # 新增一个
    def post(self, request):
        # 反序列化
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)


class BookDetailAPIView(GenericAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

    # 获取单个
    def get(self, request, pk):  # pk会自动传入 不同管
        # 查出单个
        obj = self.get_object()
        # 序列化
        ser = self.get_serializer(obj)
        return Response(ser.data)

    # 删除单个
    def delete(self, request, pk):
        # 查出单个
        obj = self.get_object()
        # 删除
        obj.delete()
        return Response()

    # 修改单个
    def put(self, request, pk):
        # 查出单个
        obj = self.get_object()
        # 反序列化
        ser = self.get_serializer(obj, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)

五个视图扩展类

作用:

提供了几种后端视图(对数据进行增删改查)处理流程的实现,如果需要编写的视图属于这5种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。

这五个扩展类要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin

ListModelMixin

列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。

该Mixin的list方法会对数据进行过滤和分页。

源码:

class ListModelMixin(object):
    """
    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)

使用:

class BookAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer
    # 获取所有
    def get(self, request):
        return self.list(request)

CreateModelMixin

创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。如果序列化器对前端发送的数据验证失败,返回400错误。

源码:

class CreateModelMixin(object):
    """
    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 {}

使用:

class BookAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer
	# 新增一个
    def post(self, request):
        return self.create(request)

RetrieveModelMixin

详细视图扩展类,提供retrieve(request, *args, **kwargs)方法, 可以快速实现返回一个存在的数据对象。如果存在,返回200,否则返回404.

源码:

class RetrieveModelMixin(object):
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        # 获取对象,会检查对象的权限
        instance = self.get_object()
        # 序列化
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

使用:

class BookDetailAPIView(GenericAPIView, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer
    # 获取单个
    def get(self, request, pk):
        return self.retrieve(request, pk)

UpdateModelMixin

更新视图扩展类,提供update(request, *args, **kwargs)方法, 可以快速实现更新一个存在的数据对象。同时也提供了partial_update(request, *args, **kwargs)方法,可以实现局部更新。成功返回200,序列化器校验数据失败时,返回400错误。

源码:

class UpdateModelMixin(object):
    """
    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)

使用:

class BookDetailAPIView(GenericAPIView, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer
    # 修改单个
    def put(self, request, pk):
        return self.update(request, pk)

DestroyModelMixin

删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。成功返回204,不存在返回404.

源码:

class DestroyModelMixin(object):
    """
    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()

使用:

class BookDetailAPIView(GenericAPIView, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer
    # 删除单个
    def delete(self, request, pk):
        return self.destroy(request, pk)

重写perform_create、update、destory方法

以下方法由mixin类提供,并提供对象保存或删除行为的简单重写。

  • perform_create(self, serializer) - 在保存新对象实例时由 CreateModelMixin 调用。
  • perform_update(self, serializer) - 在保存现有对象实例时由 UpdateModelMixin 调用。
  • perform_destroy(self, instance) - 在删除对象实例时由 DestroyModelMixin 调用。

这些钩子对于设置请求中隐含的但不是请求数据的一部分的属性特别有用。例如,你可以根据请求用户或基于URL关键字参数在对象上设置属性。

def perform_create(self, serializer):
    serializer.save(user=self.request.user)

这些可重写的关键点对于添加在保存对象之前或之后发生的行为(例如通过电子邮件发送确认或记录更新日志)也特别有用。

def perform_update(self, serializer):
    instance = serializer.save()
    send_email_confirmation(user=self.request.user, modified=instance)

你还可以使用这些钩子通过抛出 ValidationError() 来提供额外的验证。当你需要在数据库保存时应用一些验证逻辑时,这会很有用。 例如:

def perform_create(self, serializer):
    queryset = SignupRequest.objects.filter(user=self.request.user)
    if queryset.exists():
        raise ValidationError('You have already signed up')
    serializer.save(user=self.request.user)

综合使用

from .serializer import BookModelSerializer
from .models import Books
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin


class BookAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

    # 获取所有
    def get(self, request, *args, **kwargs):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class BookDetailAPIView(GenericAPIView, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

    # 获取单个
    def get(self, request, pk):
        return self.retrieve(request, pk)

    # 删除单个
    def delete(self, request, pk):
        return self.destroy(request, pk)

    # 修改单个
    def put(self, request, pk):
        return self.update(request, pk)

九个视图子类

from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveAPIView, DestroyAPIView, UpdateAPIView,ListCreateAPIView, RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView

CreateAPIView(新增一个)

提供post方法

继承自: GenericAPIView、CreateModelMixin

举例:

# 新增一个
class BookAPIView(CreateAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

ListAPIView(查询所有)

提供get方法

继承自: GenericAPIView、ListModelMixin

举例:

# 获取所有
class BookAPIView(ListAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

RetrieveAPIView(查询单个)

提供get方法

继承自:GenericAPIView、ListModelMixin

举例:

class BookDetailAPIView(RetrieveAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

DestoryAPIView(删除单个)

提供delete方法

继承自:GenericAPIView、DestoryModelMixin

举例:

class BookDetailAPIView(DestoryAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

UpdateAPIView(修改单个)

提供put和patch方法

继承自:GenericAPIView、UpdateModelMixin

举例:

class BookDetailAPIView(UpdateAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

ListCreateAPIView(查询所有、新增一个)

提供get和post方法

继承自:GenericAPIView、ListModelMixin、CreateModelMixin

举例:

class BookAPIView(ListCreateAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

RetrieveUpdateAPIView(查询单个、修改单个)

提供get、put、patch方法

继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

举例:

class BookDetailAPIView(RetrieveUpdateAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

RetrieveUpdateDestoryAPIView(查询单个、修改单个、删除单个)

提供get、put、patch、delete方法

继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

举例:

class BookDetailAPIView(RetrieveUpdateDestoryAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

RetrieveDestroyAPIView(查询单个、删除单个)

提供get、delete方法

继承自:GenericAPIView、DestoryModelMixin

举例:

class BookDetailAPIView(RetrieveDestroyAPIView):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

视图集ViewSet

使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

  • list()提供一组数据
  • retrieve()提供单个数据
  • create()创建数据
  • update()保存数据
  • destory()删除数据

ViewSet视图集类不再实现get()、post()、等方法,而是实现动作action如list()、create()等。

视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上,

只要继承ViewSetMixin的视图类,以后路由写法就特殊了

ViewSetMixin源码分析:

是为了解决两个视图类合成一个后,路由里会产生get请求会冲突的问题(不能区分是查询所有还是查询单个)

image

image

image

image

所以在设置路由的时候,我们可以这么操作:

urlpatterns = [
    path('book/', views.BookAPIView.as_view({'get': 'list', 'post': 'create'})),
    path('book/<int:pk>', views.BookAPIView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}))
]
# 这两个路由对应了一个视图类,继承了ModelViewSet,实现一个类对应5个方法

常用视图集父类

ViewSet

继承自APIViewViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{'get': 'list'})的映射处理工作。

在ViewSet中,没有提供任何动作action方法(list、create...),需要我们自己实现action方法。

GenericViewSet

使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法无需自己编写。但是Mixin扩展类依赖于GenericAPIView,所以还需要继承GenericAPIView

GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIViewViewSetMixin,在实现了调用as_view()时传入字典(如{'get': 'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

举例:

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class BookAPIView(GenericViewSet,ListModelMixin,RetrieveModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer
    
# 在urls.py中
urlpatterns = [
    path('book/', views.BookAPIView.as_view({'get': 'list'})),
    path('book/<int:pk>', views.BookAPIView.as_view({'get': 'retrieve'}))
]
# 实现了1个视图类对应了2个方法

ModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

ReadOnlyModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。

视图集中定义附加action动作

在视图集中,除了上述默认的方法动作外,还可以添加自定义动作。

举例:

class BookAPIView(ReadOnlyModelViewSet):
    queryset = Books.objects.all()
    serializer_class = BookModelSerializer

    def lqz(self, request):
        return Response('lqz')

urls.py内

urlpatterns = [
    path('admin/', admin.site.urls),
    path('book/', views.BookAPIView.as_view({'get': 'lqz'}))
]

image

总结

#两个基类
APIView
GenericAPIView:有关数据库操作,queryset 和serializer_class


#5个视图扩展类(rest_framework.mixins)
CreateModelMixin:create方法创建一条
DestroyModelMixin:destory方法删除一条
ListModelMixin:list方法获取所有
RetrieveModelMixin:retrieve获取一条
UpdateModelMixin:update修改一条

#9个子类视图(rest_framework.generics)
CreateAPIView:继承CreateModelMixin,GenericAPIView,有post方法,新增数据
DestroyAPIView:继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
ListAPIView:继承ListModelMixin,GenericAPIView,有get方法获取所有
UpdateAPIView:继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
RetrieveAPIView:继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条


ListCreateAPIView:继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
RetrieveDestroyAPIView:继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
RetrieveUpdateAPIView:继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除

#视图集
ViewSetMixin:重写了as_view 
ViewSet:     继承ViewSetMixin和APIView

GenericViewSet:继承ViewSetMixin, generics.GenericAPIView
ModelViewSet:继承mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet
ReadOnlyModelViewSet:继承mixins.RetrieveModelMixin,mixins.ListModelMixin,GenericViewSet


### 总结:如果路由想写成特殊的,如果要继承APIView----》直接继承ViewSet
### 总结:如果路由想写成特殊的,如果要继承GenericAPIView----》直接继承

image

posted @ 2022-04-01 19:39  zong涵  阅读(63)  评论(0编辑  收藏  举报