2个视图基类,5个视图扩展类,9个视图子类,视图集,drf自动生成路由

两个视图基类

APIView


GenericAPIView

# 导入
from rest_framework.generics import GenericAPIView


类GenericView 继承了APIView,

class GenericAPIView(views.APIView):
   # 这里面定义了两个参数
   queryset = None
   serializer_class = None
   
   # 记住3个方法    
   def get_queryset(self)  # 获取所有数据,查询所有需要用到
   def get_object(self):   # 查询单个对象,需要用到
       
   def get_serializer(self, *args, **kwargs)
  ...
  return serializer_class(*args, **kwargs)# 使用这个方法得到序列化类的对象,可以传selif.get_serializer(instance,data,many)
   
   def get_serializer_class(self)
  ...
  return self.serializer_class
继承了GenericAPIView类的视图层类如下:
class BookGeneric(GenericAPIView):
   queryset = Book.objects.all()
   serializer_class = BookModelSerializers

   # 查询所有
   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,*args, **kwargs):
       pass


class BookDetailGeneric(GenericAPIView):
   queryset = Book.objects.all()
   serializer_class = BookModelSerializers

   # 修改某一个
   def put(self, request, pk):
       obj = self.get_object().filter(pk=pk).first()
       ser = self.get_serializer(obj, data=request.data)
       return Response(ser.data)
   
   def get(self, request, pk):
       pass
   
   def delete(self, request,pk):
       pass

五个视图扩展类(没有继承其他类)

# 导入5个视图扩展类
# mixins.py
from rest_framework.mixins import CreateModelMixin,ListModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
# 查询所有,ListModelMixin,
# 新增 CreateModelMixin,

# 查询单个 RetrieveModelMixin
# 更新某个 UpdateModelMixin
# 删除某个 DestoryModelMixin
继承GenericAPIView类 和视图扩展类的视图类
# 当有了上面5个视图扩展类以后,就可以在我们自己写的视图类中*组合的继承他们,实现不同的接口功能
# 记得这里写了一个小作业,继承GenericAPIView和一个自己写的类,在新建视图类中只配置那两个参数,即可实现5个接口
# 如下,为一个查询所有和新增的方法
class BookGenericList(GenericAPIView, ListModelMixin, CreateModelMixin):
   queryset = Book.objects.all()
   serializer_class = BookModelSerializers

   def get(self, request, *args, **kwargs):
       return self.list(request, *args, **kwargs)

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

9个视图子类

现在,改写一下上述视图类,编写视图类继承视图子类实现同样的功能,并且实现了代码少量书写;

# 导入视图子类
# rest_framework.generics

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

视图类

# 此时我们只需要在自己写的视图类中继承视图子类ListCreateAPIView,就可以实现对数据的查询所有,和增加一条
class BookListCreate(ListCreateAPIView):
   queryset = Book.objects.all()
   serializer_class = BookModelSerializers
# 删除一条数据
class BookDestory(DestoryAPIView):
   queryset = Book.objects.all()
   serializer_class = BookModelSerializers

视图集

可以看到视图类继承视图子类之后的视图类写法变简洁了,但是可以看见,上面两个视图类除了类名和继承的类不一样,下面的代码主体一样。使用视图集以后,能否将5个接口写在一个视图类中。请看下边

# 导入视图集类
from rest_framework.viewsets import ModelViewSet,GenericViewSet,ViewSetMixin,ReadOnlyModelViewSet,ViewSet
         

路由

    # 使用视图集的视图类的url
   path('bookviewset', views.BookViewSet.as_view({'get': 'list', 'post': 'create'})),
   path('bookdetailviewset/<int:pk>', views.BookViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}))

实现5个接口的视图类

# 只继承了一个视图集ModelViewSet类就实现了5个接口的功能
class BookViewSet(ModelViewSet):
   queryset = Book.objects.all()
   serializer_class = BookModelSerializers

有点绕的东西

class ModelViewSet(mixins.CreateModelMixin,
                  mixins.RetrieveModelMixin,
                  mixins.UpdateModelMixin,
                  mixins.DestroyModelMixin,
                  mixins.ListModelMixin,
                  GenericViewSet):
   
from rest_framework.generics  
class GenericViewSet(ViewSetMixin, GenericAPIView):
   pass

# 还是要抓住那个cls,以及cls实例化出来的对象
class ViewSetMixin:
   @classonlymethod
   def as_view(cls, actions=None, **initkwargs):
       """
      Because of the way class based views create a closure around the
      instantiated view, we need to totally reimplement `.as_view`,
      and slightly modify the view function that is created and returned.
      """
       # The name and description initkwargs may be explicitly overridden for
       # certain route configurations. eg, names of extra actions.
       cls.name = None
       cls.description = None
       cls.suffix = None
       cls.detail = None
       cls.basename = None
       if not actions:
           raise TypeError("The `actions` argument must be provided when "
                           "calling `.as_view()` on a ViewSet. For example "
                           "`.as_view({'get': 'list'})`")
       for key in initkwargs:
           if key in cls.http_method_names:
               raise TypeError("You tried to pass in the %s method name as a "
                               "keyword argument to %s(). Don't do that."
                               % (key, cls.__name__))
           if not hasattr(cls, key):
               raise TypeError("%s() received an invalid keyword %r" % (
                   cls.__name__, key))

       # name and suffix are mutually exclusive
       if 'name' in initkwargs and 'suffix' in initkwargs:
           raise TypeError("%s() received both `name` and `suffix`, which are "
                           "mutually exclusive arguments." % (cls.__name__))

       def view(request, *args, **kwargs):
           self = cls(**initkwargs)

           if 'get' in actions and 'head' not in actions:
               actions['head'] = actions['get']

           # We also store the mapping of request methods to actions,
           # so that we can later set the action attribute.
           # eg. `self.action = 'list'` on an incoming GET request.
           self.action_map = actions

           # Bind methods to actions
           # This is the bit that's different to a standard view
           for method, action in actions.items():
               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)

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

drf自动生成路由

# 导自动生成路由的类
from rest_framework.routers import Simplerouter

# 实例化得到对象
router = Simplerouter()
# 注册路由
router.register('路径',对应的自己写的视图类)
# 路由地址的列表
router.urls
# 与路由层的urlpatterns 进行拼接
urlpatterns += router.urls

还有一种写法
from django.urls import path,include

urlpatterns = [
   path('', include(router.urls)),
   # 也可以拼接路径
   path('api/v1/', include(router.urls)),
]



上一篇:单例模式


下一篇:Python中如何控制类的实例化过程