drf : 通用视图类和(GenericAPIView)5个视图扩展类,九个视图子类,视图集。

视图

REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。

APIView

rest_framework.views.APIView

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

GenericAPIView使用[通用视图类]

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

点击第一层查看代码
from rest_framework.views import APIView
from .serizlizer import BookSerializers
from rest_framework.response import Response
from .models import Books
from rest_framework import status
from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer


class BookView(APIView):
    renderer_classes = [JSONRenderer]

    # 创建数据反序列化
    def post(self, request):
        print(request)
        ser = BookSerializers(data=request.data)
        if ser.is_valid():
            ser.save()
        return Response(ser.data)

    # 读取序列化
    def get(self, request):
        print(request)
        book_list = Books.objects.all()
        # many=True 代表序列化多条数据
        ser = BookSerializers(instance=book_list, many=True)
        """
        <class 'rest_framework.serializers.ListSerializer'>
        ser 是ListSerializer的对象
        """
        print(type(ser))
        response = {'code': 100, 'msg': '查询成功', 'result': ser.data}
        #
        return Response(response, status=status.HTTP_202_ACCEPTED, headers={'name': 'junjie'})


# 查询单条
class BookDetailView(APIView):
    def get(self, request, pk):
        book = Books.objects.filter(pk=pk).first()
        # 不传many默认为,many=False
        ser = BookSerializers(instance=book)
        """
        <class 'app01.serizlizer.BookSerializers'>
        ser是BookSerializers的对象
        """
        print(type(ser))
        """
        BookSerializers(instance=<Books: Books object (1)>):
        id = IntegerField(label='ID', read_only=True)
        name = CharField(max_length=32)
        price = IntegerField()
        publish = PrimaryKeyRelatedField(allow_null=True, queryset=Publish.objects.all(), required=False)
        """
        print(ser)
        # 这一步才是真正将book_list转为字典并返回。调ser.data才是真正的序列化过程
        return Response(ser.data)

    # 删除单条数据
    def delete(self, request, pk):
        Books.objects.filter(pk=pk).delete()
        return Response()

    # 修改
    def put(self, request, pk):
        print(request)
        book = Books.objects.filter(pk=pk).first()
        # 得到模型层Book表对象。
        print(book.name)
        # {'name': '第11条数据', 'price': 20200, 'publish': 1} 反序列化数据。
        print(request.data)
        # 字典
        print(type(request.data))
        ser = BookSerializers(instance=book, data=request.data)
        print(ser)
        # <class 'app01.serizlizer.BookSerializers'>
        print(type(ser))
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
class BookView(APIView):
    renderer_classes = [JSONRenderer]

    # 创建数据反序列化
    def post(self, request):
        ser = BookSerializers(data=request.data)
        if ser.is_valid():
            ser.save()
        return Response(ser.data)

    # 读取序列化
    def get(self, request):
        book_list = Books.objects.all()
        # many=True 代表序列化多条数据
        ser = BookSerializers(instance=book_list, many=True)

        response = {'code': 100, 'msg': '查询成功', 'result': ser.data}
        return Response(response, status=status.HTTP_202_ACCEPTED, headers={'name': 'junjie'})


# 查询单条
class BookDetailView(APIView):
    def get(self, request, pk):
        book = Books.objects.filter(pk=pk).first()
        ser = BookSerializers(instance=book)
        return Response(ser.data)

    def delete(self, request, pk):
        Books.objects.filter(pk=pk).delete()
        return Response()

    # 修改
    def put(self, request, pk):
        book = Books.objects.filter(pk=pk).first()
        ser = BookSerializers(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)

GenericAPIView[通用视图类]的方法属性以及方法,第二层的演变。

  • 属性
    • serializer_class指明视图使用的序列化器
  • 方法
    • get_serializer_class(self)

现在来想继承GenericAPIView来写视图函数改如何写?先查看GenericAPIView类定义了什么属性和方法。

图书的五个接口,第二层,精简模型类和序列化类

from .models import Books, Publish
from rest_framework.generics import GenericAPIView
from .serizlizer import BookSerializers, PublishSerializers
from rest_framework.response import Response


class BookAPIView(GenericAPIView):
    queryset = Books.objects.all()
    serializer_class = BookSerializers

    def get(self, request):
        book_list = self.get_queryset()
        ser = self.get_serializer(instance=book_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 BookDetailView(GenericAPIView):
    queryset = Books.objects.all()
    serializer_class = BookSerializers

    def get(self, request, pk):
        book_list = self.get_object()
        ser = self.get_serializer(instance=book_list)
        return Response(ser.data)

    def put(self, request, pk):
        book_obj = self.get_object()
        # 得到序列化类对象,传入单条对象和要修改的数据字段
        ser = self.get_serializer(instance=book_obj, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)

    def delete(self, request, pk):
        book = self.get_object()
        book.delete()
        return Response()

如果想要再写一个视图类只需要继承GenericAPIView修改queryset和serializer_class即可,那么有没有别的方法可以节省代码?

使用GenericAPIView+5个视图扩展类。

from rest_framework.mixins import 
CreateModelMixin, # 创建单个
ListModelMixin, # 查询所有
DestroyModelMixin, # 删除单个 碟嘶踹
UpdateModelMixin, # 新建单个
RetrieveModelMixin # 查询单个 瑞吹雾

代码如下:

from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
    ListModelMixin
from rest_framework.generics import GenericAPIView
from .models import Books, Publish
from .serizlizer import BookSerializers, PublishSerializers


class BookAPIView(GenericAPIView,
                  # 创建数据                  
                  CreateModelMixin,
                  # 查看所有
                  ListModelMixin):
    queryset = Books.objects.all()
    serializer_class = BookSerializers

    def get(self, request):
        print(request)
        return self.list(request)

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


class BookDetailView(GenericAPIView,
                     UpdateModelMixin,    # 修改单条数据
                     DestroyModelMixin,   # 删除单条
                     RetrieveModelMixin): # 查询单条
    queryset = Books.objects.all()
    serializer_class = BookSerializers

    def get(self, request, pk):
        print(request)
        return self.retrieve(request, pk)

    def delete(self, request, pk):
        print(request)
        return self.destroy(request, pk)

    def put(self, request, pk):
        return self.update(request, pk)

为什么叫视图扩展类:因为他不是视图类,视图类必须是继承View/APIView。

还有没有办法再精简代码?

GenericAPIView的视图子类,第三层

1)CreateAPIView

提供 post 方法

继承自: GenericAPIView、CreateModelMixin

2)ListAPIView

提供 get 方法

继承自:GenericAPIView、ListModelMixin

3)RetrieveAPIView

提供 get 方法

继承自: GenericAPIView、RetrieveModelMixin

4)DestoryAPIView

提供 delete 方法

继承自:GenericAPIView、DestoryModelMixin

5)UpdateAPIView

提供 put 和 patch 方法

继承自:GenericAPIView、UpdateModelMixin

以及:

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


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


class BookDetailAPIView(RetrieveUpdateDestroyAPIView):
    queryset = Books.objects.all()
    serializer_class = BookSerializers

总结:

#两个基类
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删除

第五层,直接写五个接口最终演示,自动生成路由。

from rest_framework.viewsets import ModelViewSet

# ModelViewSet继承了5个视图扩展类,GenericViewSet 和 ViewSetMixin
class BookAPIView(ModelViewSet):
    queryset = Books.objects.all()
    serializer_class = BookSerializers

继承五个视图扩展类的作用为用了五个接口方法。

GenericViewSet是什么?

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default,
    but does include the base set of generic view behavior, such as
    the `get_object` and `get_queryset` methods.
    """
    pass
  
  
"""
已知:generics.GenericAPIView 中有View和APIView,以及四个方法
    def get_queryset(self):
       
    def get_object(self):
      
    def get_serializer(self, *args, **kwargs):
    
    def get_serializer_class(self):
"""

ViewSetMixin

class ViewSetMixin:

    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):

        cls.name = None
        cls.description = None

        cls.suffix = None

        cls.detail = None

        cls.basename = None

        # 注释:
				"""
				此处与url相对应,actions是什么?
				path('books/', views.BookAPIView.as_view({'get':'list','post':'create'})),
				actions = {'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'})`")
            # 注释:
  	    """
  	    字典.items()是将K,V拆出,此时method=K,action=V
            以{'get':'list','post':'create'}举例。
  	    get = method,list = action
  	    """
            for method, action in actions.items():
              	# 注释:
                """
                此时的self为视图类对象BookAPIView
                action是上述所讲的url,as_view的第一个参数。
                
                getattr反射,此时视图类对象中没有list,到父类ModelViewSet --> 
                mixins.ListModelMixin -->  def list(self, request, *args, **kwargs):
                
                handler 便是反射出来的list
                
                setattr设置值,将list映射成get,视图中的get方法实质上是list方法。
                客户端发送get请求就能找到list
                这里主要用作区分用户是查询单条还是查询所有
                """
                handler = getattr(self, action)
                setattr(self, method, handler)

            self.request = request
            self.args = args
            self.kwargs = kwargs

            # And continue as usual
            return self.dispatch(request, *args, **kwargs)

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())

        # We need to set these on the view function, so that breadcrumb
        # generation can pick out these bits of information from a
        # resolved URL.
        view.cls = cls
        view.initkwargs = initkwargs
        view.actions = actions
        return csrf_exempt(view)

第五层

导入模块

from rest_framework.viewsets import ModelViewSet

直接写五个接口最终演示,自动生成路由。

from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet, GenericViewSet, ViewSet


# 直接写五个接口,一定要继承(ViewSetMixin),才能自动生成路由
# class BookAPIView(ModelViewSet):
#     queryset = Books.objects.all()
#     serializer_class = BookSerializers

# 查询所有和查询单个,如果只继承了ReadOnlyModelViewSet,路由也需要更改。
# class BookAPIView(ReadOnlyModelViewSet):
#     queryset = Books.objects.all()
#     serializer_class = BookSerializers


# GenericViewSet:继承了(ViewSetMixin, generics.GenericAPIView)

# ViewSet:继承了(ViewSetMixin, views.APIView)


class BookAPIView(ViewSet):
    def xjz(self, request):
        return Response("junjie")

url

# 自动生成路由
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
# 必须继承(ViewSetMixin),才能自动生成路由
router.register('books', views.BookAPIView)

urlpatterns = [
    path('admin/', admin.site.urls),

    # 将请求映射到对应的方法
    path('books/', views.BookAPIView.as_view({'get':'list'})),
    path('books/<int:pk>', views.BookAPIView.as_view({'get':'retrieve'})),
]

urlpatterns += router.urls

导入模块

from rest_framework.routers import SimpleRouter
from django.urls import path,include
router = SimpleRouter()
# 必须继承(ViewSetMixin),才能自动生成路由
router.register('admin', views.BookAPIView)

urlpatterns = [
    # path('admin/', admin.site.urls),

    path('api/',include(router.urls))
]

此时浏览器访问admin的路由:http://127.0.0.1:8000/api/admin/

posted @ 2022-04-01 20:52  谢俊杰  阅读(122)  评论(0编辑  收藏  举报