教程3–基于类的视图
本人英语巨渣,文章都是瞎翻译的,如有雷同,纯属巧合~
除了使用基于函数的视图,我们也可以使用基于类的视图。由于类视图的可复用性,我们可以缩减很多代码,这也体现了DRY原则。
这一篇主要内容就是改写之前的写的视图,各种花式改编,最后你就会发现,原来一个基于模型的视图类原来可以寥寥几行代码就搞定了。
使用基于类的视图重写之前的案例
class SnippetList(APIView):
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):
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, 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)
相对应的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'^snippet/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view())
]
urlpatterns = format_suffix_patterns(urlpatterns)
从上面的例子看,似乎改写成基于类的视图以后,程序也没有多大的改变,基于类的视图真有那么好吗?别急,下面就让基于类的视图发挥威力。
使用mixin
使用基于类的视图一个最大的优势就是可以让我们简单地组合可重用的行为来完成复杂的动作。
不知大家有没有发现,我们在上述例子中一直在写的create/retrieve/update/delete这些行为,其实不管对于那种模型,需要完成的行为都是差不多的。那么这些行为就可以说是公共行为了。这些公共行为被REST框架实现成了一个个的mixin。
让我们来看一看如何使用mixin来改写之前的案例:
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)
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)
是不是感觉简单多了?mixin帮我们做了大部分的操作。我们已经不用自己写逻辑去操作serializer了~
然而,貌似这里每个方法都是直接调用了mixin的方法而已,这样的话我们为什么不封装一个通用一点的视图出来?
放心,REST早就想到了。
使用通用视图
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
对比一下前后程序的代码量,感受类视图的魅力吧。