欢迎关注个人微信公众号,大大大碗面,不定期分享AI论文解读和开发技术,互联网小白,轻喷~
重构一下snippets/view.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):
"""
列出所有已经存在的snippet或者创建一个新的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)
到这里应该很容易理解,和原来的相比,可以发现基于类的视图把各种不同的HTTP请求分离开变成单个的方法,而不是if...elif...
这样的结构,所以这样处理起来很更加的高效。
同样的,把另一个视图函数snippet_detail
也进行修改:
class SnippetDetail(APIView):
"""
检索查看、更新或者删除一个snippet
"""
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)
改为基于类的视图之后,当然也要修改一下路由了,对 snippets/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[0-9]+)/$' , views.SnippetDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
这样就可以运行程序了,功能和之前的是一样的
使用基于类的视图的好处除了上面所说的把各种HTTP请求分离开,还有什么好处吗?答案是肯定的——使用基于类的视图的最大优势之一是它可以轻松地构成可重复使用的行为。
可重复使用的行为?简单说,就是让我们少写一点功能类似的代码,由此就要介绍一下mixins类了,它帮我们封装了很多操作,简化代码,使用也很简单,编辑snippets/view.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)
新的视图类中继承了 generic.GenericAPIView、mixins.ListModelMixin 和 mixins.CreatteModelMixin,类的作用看字面意思就能懂啦,mixins类为我们提供了list()和create()方法,当然,使用这两个函数需要先设置queryset和serializer_class,这点我们查看一下mixins的源码就可以看出来了,比如list方法:
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
这里的代码会分别通过 get_queryset() 和 get_serializer() 得到查询集和序列化器,其他封装好的方法也是如此。
知道了这个,在修改一下另一个视图类就很容易了:
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)
到这里,视图代码已经简化了很多了,但是其实还可以进一步简化:
进一步简化就是连mixins类都不用了,只使用generics就可以了,代码如下:
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