Django编写Restful-Api:类视图

在上一篇文章中,主要讲的是请求和响应,项目里面views.py中的视图函数都是基于函数的,并且我们介绍了@api_view这个很有用的装饰器。同时,我们还介绍了APIView这个类,但是还没使用它。在这篇文章中,我们要做的是把基于方法的视图改为基于类的视图,将会了解到APIView


改为基于类的视图

重构一下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...这样的结构,所以这样处理起来很更加的高效。

同样的,把另一个视图函数也进行修改:

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<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

使用mixins类

使用基于类的视图的好处除了上面所说的把各种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.GenericAPIViewmixins.ListModelMixinmixins.CreatteModelMixin,类的作用看字面意思就能懂啦,mixins类为我们提供了list()create()方法,当然,使用这两个函数需要先设置querysetserializer_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)

使用generics视图类

到这里,视图代码已经简化了许多了,但是我要告诉你的是,还可以进一步简化。进一步简化就是连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

好了,现在的代码就显得非常简洁了,但是短小却精悍,依然可以实现原本的功能。


测试Api

测试方法和上篇雷同,可跳过。

http http://127.0.0.1:8000/snippets/

mark

  1. 通过设置Accept头部信息来控制返回的格式
http http://127.0.0.1:8000/snippets/ Accept:application/json  # JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html # HTML

效果如下(返回的是页面的HTML代码,只展示了一部分):

mark

  1. 直接加格式后缀
http http://127.0.0.1:8000/snippets.json  # JSON suffix
http http://127.0.0.1:8000/snippets.api # Browsable API suffix
  1. 浏览器查看Api

我们可以直接在浏览器输入 http://127.0.0.1:8000/snippets.api 进行查看,会得到一个美观的页面:
mark

增加数据

我们可以控制 Content-Type 头部信息来提交POST请求:

http --form POST http://127.0.0.1:8000/snippets/ code="print 123"
http --json POST http://127.0.0.1:8000/snippets/ code="print 456"

它会自动在原有的数据后面添加你提交过去的数据,效果如下:

mark

修改数据

我们通过PUT来实现修改功能,在我们之前定义的函数views.snippet_detail中:

url(r'^snippets/(?P<pk>[0-9]+)$', views.snippet_detail),

所以通过 url snippets/[id]就可以访问到我们要的数据,就可以对其进行修改。

http --json PUT http://127.0.0.1:8000/snippets/1.json code="sss"

mark

删除数据

同之前的修改一样,我们使用DELETE,通过 url snippets/[id]访问数据,提交删除。

http DELETE http://127.0.0.1:8000/snippets/8.json

这样我们就成功的删除了一条数据。


声明

本篇文章来自ziv的博客,仅作整理学习分享。
点击这里访问原文


-------------本文结束感谢您的阅读-------------