drf 视图类、视图集、路由
一、视图类
1、写 publish: 查询所有,查询单条,修改一条,新增一条,删除一条的接口
class PublishView(ListCreateAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer class PublishDetailView(RetrieveUpdateDestroyAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer
2、写 publish 查询单条,新增一条的接口--->使用9个视图子类编写
class PublishView(CreateAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer class PublishDetailView(RetrieveAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer
3、写 publish: 查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView
class PublishView(GenericAPIView,CreateModelMixin): queryset = Publish.objects.all() serializer_class = PublishSerializer def post(self,request,*args,**kwargs): return self.create(request,*args,**kwargs)
class PublishDetailView(GenericAPIView,RetrieveModelMixin): queryset = Publish.objects.all() serializer_class = PublishSerializer def get(self,request,*args,**kwargs): return self.retrieve(request,*args,**kwargs)
二、视图集
1、
from rest_framework.viewsets import ModelViewSet class PublishView(ModelViewSet): queryset = Publish.objects.all() serializer_class = PublishSerializer class PublishDetailView(ModelViewSet): queryset = Publish.objects.all() serializer_class = PublishSerializer
2、修改路由
在路由.as_view()中:写一个字典,请求方法对应接口增删改查方法
urlpatterns = [ path('publishs/', PublishView.as_view({'get': 'list', 'post': 'create'})), path('publishs/<int:pk>', PublishDetailView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), ]
3、
ModelViewSet---> 继承了五个扩展类 + GenericViewSet----> ViewSetMixin(决定了路由的新写法)----> as_view()(多了action)---->view(request)
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):
问一:
查询所有接口 -get--list----> 拿到所有数据,序列化--返回。
新增一条 -post---create---> 之前写的新增的代码一样的
答一:
由于继承了5个扩展类,序列化、反序列化、数据校验都有了
问二:
为什么get 就变成了list ?为什么post 就变成了create
答二:ViewSetMixin类重新封装了as_view(),使得请求方式可以对应方法
path('publishs/', PublishView.as_view({'get': 'list', 'post': 'create'}))
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
# ViewSetMixin必须在左侧,保障了as_view是ViewSetMixin的as_view Overrides `.as_view()` so that it takes an `actions` keyword that performs the binding of HTTP methods to actions on the Resource.
view()
-class GenericViewSet(ViewSetMixin, generics.GenericAPIView):ViewSetMixin必须放前面--》保证执行的as_view是ViewSetMixin的 -请求来了,路由匹配成功---》执行ViewSetMixin的as_view内的view(request) def view(request, *args, **kwargs): self = cls(**initkwargs) # 类实例化得到对象--》self是谁的对象?PublishView self.action_map = actions # {'get':'list','post':'create'} # method:get # action: list for method, action in actions.items(): # list 方法 handler = getattr(self, action) #PublishView对象中反射list,拿到了 # 反射设置值 #setattr(PublishView视图类的对象,get,list 方法) # PublishView视图类的对象中就会有一个get方法,就是list setattr(self, method, handler) return self.dispatch(request, *args, **kwargs) # 总结: -路由中这样配置:PublishView.as_view({'get':'list','post':'create'}) -以后get请求过来,本质执行的就是视图类中的list方法
4、视图层中类的总结
# 1 两个视图基类 -APIView和GenericAPIView -APIView的执行流程:包装了新的 处理了csrfrequeset,执行了3大认证,处理全局异常 -GenericAPIView:要做序列化,要跟数据库打交道,就直接继承它即可 -queryset -serializer_class -get_object -get_queryset -get_serializer # 2 5个视图扩展类(不是视图类),需要GenericAPIView才能用 -快速使用5个接口 -某几个接口:查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView class PublishView(GenericAPIView,CreateModelMixin) queryset=Publish.objects.all() serializer_class=序列化类 def post(self,request) return self.create(request) class PublishDetailView(GenericAPIView,RetrieveModelMixin) queryset=Publish.objects.all() serializer_class=序列化类 def get(self,request) return self.retrieve(request) # 3 9个视图子类(继承GenericAPIView+5个视图扩展类的组合) ListAPIView, CreateAPIView ListCreateAPIView RetrieveAPIView, DestroyAPIView, UpdateAPIView RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView # 4 视图集 -ModelViewSet: -ViewSetMixin+GenericAPIView+5个视图扩展类 -GenericViewSet+5个视图扩展类 -ViewSetMixin源码:路由做映射的配置,以后视图类中方法可以随便命名 -Viewset:ViewSetMixin+APIView---》不需要要序列化,路由写法变了 -GenericViewSet:ViewSetMixin+GenericAPIView--》需要序列化,需要用数据库,路由写法变化 -ReadOnlyModelViewSet:list和retrieve
5、
from rest_framework.viewsets import ViewSetMixin, ViewSet, GenericViewSet ## 不和数据库打交道 # class UserView(ViewSetMixin, APIView): # class UserView(ViewSet): # ViewSet = ViewSetMixin + APIView # def register(self, request): # return Response('registered') ## 跟数据库打交道 # class UserView(ViewSetMixin, GenericAPIView): class UserView(GenericViewSet): # GenericViewSet = ViewSetMixin + GenericAPIView def register(self, request): return Response('registered') def login(self, request): return Response('login')
路由:
path('users/', UserView.as_view({'post': 'register'})),
由上可知: 之前只能填写post、get、put、delete方法名的现在可以随意命名了
6、
# 以后写的接口,只想有 获取单条和获取所有,继承它
三、路由
1、之前的路由写法
path('books/', BookView.as_view())
视图集ModelViewSet 继承了ViewSetMixin (改写了as_view()),路由改变
path('publish/', PublishView.as_view({'get': 'list', 'post': 'create'}))
这样写法做映射,可能有些麻烦,于是drf,帮咱们封装了两个路由类---》可以帮助咱们快速生成之前咱们写的映射关系
## 自动生成路由:自动映射如下: {'get': 'list', 'post': 'create'} {'get': 'retrieve', 'put': 'update', 'delete': 'destroy'} ## 其他的-->视图类中有别的方法,我们想做映射,需要使用装饰器
2、使用方法
大前提:必须是继承ViewSetMixin+APIView及其子类才能自动生成
####使用步骤 # urls.py中 #### 1 导入路由类 from rest_framework.routers import SimpleRouter, DefaultRouter #### 2 类实例化得到对象 router = SimpleRouter() #### 3 自动生成路由,调用对象的某个方法,完成跟视图类的对应关系,映射路由 router.register('publish', PublishView, 'publish') # 三个参数:路径、视图类名、别名 # router.register('books', BookView, 'books') # 后期可以注册更多 router.register('user',UserView,'user') ##### 4 把自动生成的路由,加到总路由中 urlpatterns = urlpatterns + router.urls # 两个列表直接相加 ### 第四步可以这样写 path('api/v1/', include(router.urls)), # http://127.0.0.1:8008/api/v1/user/register/--->post
3、
SimpleRouter, DefaultRouter区别 -DefaultRouter生成的路径多一个根路径 api-root -DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据 以后就用:SimpleRouter就可以
4、