DRF终极封装ViewSet和Router附教程PDF源码 (2)

viewsets.ModelViewSet包含了增删改查视图集合,源码如下:

class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass

它继承了mixins.CreateModelMixin、mixins.RetrieveModelMixin、mixins.UpdateModelMixin、mixins.DestroyModelMixin、mixins.ListModelMixin、GenericViewSet:

其中mixins.RetrieveModelMixin、mixins.ListModelMixin和GenericViewSet在前面已经介绍过了

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) 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 {}

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

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() 修改URLConf

视图改为ViewSet后,需要同时修改URLConf,编辑snippets/urls.py:

from snippets.views import SnippetViewSet, UserViewSet, api_root from rest_framework import renderers snippet_list = SnippetViewSet.as_view({ 'get': 'list', 'post': 'create' }) snippet_detail = SnippetViewSet.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }) snippet_highlight = SnippetViewSet.as_view({ 'get': 'highlight' }, renderer_classes=[renderers.StaticHTMLRenderer]) user_list = UserViewSet.as_view({ 'get': 'list' }) user_detail = UserViewSet.as_view({ 'get': 'retrieve' }) urlpatterns = format_suffix_patterns([ path('', api_root), path('snippets/', snippet_list,), path('snippets/<int:pk>/', snippet_detail,), path('snippets/<int:pk>/highlight/', snippet_highlight,), path('users/', user_list,), path('users/<int:pk>/', user_detail,) ])

注意,ViewSet需要绑定http methods和action,以指定请求方法对应的处理动作。

Routers

使用ViewSet的一大好处是可以自动配置路由,DRF提供了rest_framework.routers:

image-20201221160635729

我们重新编写snippets/urls.py看看是什么效果:

from django.urls import path, include from rest_framework.routers import DefaultRouter from snippets import views # Create a router and register our viewsets with it. router = DefaultRouter() router.register(r'snippets', views.SnippetViewSet) router.register(r'users', views.UserViewSet) # The API URLs are now determined automatically by the router. urlpatterns = [ path('', include(router.urls)), ]

真是厉害!这封装简直高级!而且DefaultRouter提供了API根目录的Endpoint,我们甚至可以把views.py中的api_root也删了。

东方说

本文是官方教程学习笔记的最后一篇了。可以从教程中了解到从函数视图到类视图,从View到ViewSet是如何封装起来的,实际运用中并不一定全部都得用类视图和ViewSet,还是需要平衡选择。后续还会有DRF系列的文章输出,不过作为阶段性成果,我把这7篇文章导成了PDF,和最后一版的源码,打包一起上传了,需要的话,可以在公众号后台回复【drf】获取:

image-20201221171351224

参考资料:

https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxpdg.html