此文档为官方文档的翻译,原文地址:https://www.django-rest-framework.org/tutorial/3-class-based-views/
我们也可以使用类视图来取代原始的函数视图。待会你会发现类视图原来如此强大,强大到你的代码简洁的跟Hello World一样。
用类视图重写API
from snippets.models import Snippetfrom snippets.serializers import SnippetSerializerfrom django.http import Http404from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import statusclass SnippetList(APIView):"""列出所有Snippet,或者创建一个新的Snippet"""def get(self, request, format=None):snippets = Snippet.objects.all()serializer = SnippetSerializer(snippets, many=True) # 当序列化对象类型为QuerySet时,记得使用many这一关键字参数哦~return Response(serializer.data)def post(self, request, format=None):serializer = SnippetSerializer(data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data, status=status.HTTP_201_CREATED)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
怎么样,这是不是很清爽,也很Django?
同样的操作,改一下实例视图:
class SnippetDetail(APIView):"""检索、更新或删除一个Snippet实例。"""def get_object(self, pk):try:return Snippet.objects.get(pk=pk)except Snippet.DoesNotExist:raise Http404def get(self, request, pk, format=None):snippet = self.get_object(pk)serializer = SnippetSerializer(snippet)return Response(serializer.data)def put(self, request, pk, format=None):snippet = self.get_object(pk)serializer = SnippetSerializer(snippet, data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)def delete(self, request, pk, format=None):snippet = self.get_object(pk)snippet.delete()return Response(status=status.HTTP_204_NO_CONTENT)
重构完了视图,也要重构url,像之前使用Django一样:
from django.urls import pathfrom rest_framework.urlpatterns import format_suffix_patternsfrom snippets import viewsurlpatterns = [path('snippets/', views.SnippetList.as_view()),path('snippets/<int:pk>/', views.SnippetDetail.as_view()),]urlpatterns = format_suffix_patterns(urlpatterns)
OK,重构结束!如果你没出什么岔子,整个项目还能像之前一样运行。
修改完代码,结构上确实优雅了,不过,这工作量和之前也没减少多少呀……
别急,玩斗地主哪有一开始就放王炸的,耐心看下去~
使用 Mixin
使用基于类的视图的一大优点是:它允许我们轻松地组合可重用的行为。
到目前为止,我们使用的create/retrieve/update/delete 操作对于我们创建的任何模型支持的 API 视图来说都非常相似。
DRF将这些常用的操作抽象提取畜类,这就成了DRF中的Mixin类。
我们再来重构一下视图:
from snippets.models import Snippetfrom snippets.serializers import SnippetSerializerfrom rest_framework import mixinsfrom rest_framework import genericsclass SnippetList(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):queryset = Snippet.objects.all() # 获取querysetserializer_class = SnippetSerializer # 获取序列化类def get(self, request, *args, **kwargs):return self.list(request, *args, **kwargs)def post(self, request, *args, **kwargs):return self.create(request, *args, **kwargs)
我们将花一点时间来检查这里到底发生了什么。我们正在使用 GenericAPIView 构建视图,并添加了 ListModelMixin 和 CreateModelMixin。
基类提供了核心功能,而mixin类提供了.list()和.create()操作。然后显式地将get和post方法绑定到相应的操作。到目前为止,这些都很简单。
class SnippetDetail(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,generics.GenericAPIView):queryset = Snippet.objects.all()serializer_class = SnippetSerializerdef get(self, request, *args, **kwargs):return self.retrieve(request, *args, **kwargs)def put(self, request, *args, **kwargs):return self.update(request, *args, **kwargs)def delete(self, request, *args, **kwargs):return self.destroy(request, *args, **kwargs)
类似的操作,我们再次使用GenericAPIView类来提供核心功能,并添加mixin来提供.retrieve()、.update()和.destroy()操作。
看到这里,你有没感到一丝丝惊喜的意味呢?
别急,Mixin还只是中级兵,下面来介绍高级兵——通用类视图。
使用通用类视图(优雅带师!)
使用mixin类重构视图后,我们的代码比以前稍微少了一些,但我们可以更进一步。
REST框架提供了一组混合的通用视图,我们可以使用它们来进一步精简views.py模块。
from snippets.models import Snippetfrom snippets.serializers import SnippetSerializerfrom rest_framework import genericsclass SnippetList(generics.ListCreateAPIView):queryset = Snippet.objects.all()serializer_class = SnippetSerializerclass SnippetDetail(generics.RetrieveUpdateDestroyAPIView):queryset = Snippet.objects.all()serializer_class = SnippetSerializer
Wow!惊不惊喜?开不开心?
50多行的代码简化到不到10行,终于体会到了那句话的精髓:
人生苦短,我用Python!
