基于类的 views
我们之前讨论的都是基于函数的 views ,也就是说所有的 views 都是以一个个函数来写的。但是,现在,我们要讲的就是以类的形式来编写 views,这样的话,每个 views 都是一个类,这有助于我们更好得重用代码,从而更好得实现 DRY。
使用基于类的 views 重写 API
打开我们的 views.py 文件,我们将它修改成:
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class SnippetList(APIView):
List all snippets, or create a new snippet.
def get(self, request, format=None):
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
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)
class SnippetDetail(APIView):
Retrieve, update or delete a snippet instance.
def get_object(self, pk):
try:
return Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
raise Http404
def 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)
好的,是不是看上去很赞。和基于函数的 views 一样的简洁,甚至更好一些。同样得,我们也需要对 urls.py 进行修改,修改成这样:
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
url(r'^snippets/$', views.SnippetList.as_view()),
url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
现在,重新运行一下你的服务试试,是不是完美得在工作。
使用 mixins
使用基于类的 views 的最大好处就是我们可以轻松重用通用代码,尤其是像增删改查这样的操作,基本上都是类似的。这些行为在 REST框架 中都通过 mixins 类被实现了。
让我们来看看使用 mixins 类实现的组件吧,还是拿我们的 views.py 模块为例:
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import mixins
from rest_framework import generics
class SnippetList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Snippet.objects.all()
serializer_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)
这里,我们集成了 generics.GenericAPIView ,然后再添加了 ListModelMixin 和 CreateModelMixin,基类提供了核心的功能,然后 mixin 类提供了 .list 和 .create 功能。然后我们实现 get 和 post 方法用于响应请求。
class SnippetDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
def 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)
我们用同样的方式实现 SnippetDetail。
使用基于通用类的 views
使用 mixin类 之后,我们发现代码节省了很多,但是,我们还可以更进一步。REST框架 提供了一些 mixed-in 的通用 view,可以帮助我们实现更简洁的 views。
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
哇喔,看看我们的代码,多么简介啊,这才是 django 的魅力啊!代码良好,结构清晰,阅读顺畅。