Django Rest Framework:进一步理解序列化之基于类的视图

一,基于类的视图

REST framework 提供了一个 APIView 类,它是 Django 的 View 类的子类。基于类的视图必须继承APIView类。

  • 传递给处理程序方法的请求将是 REST framework 的 Request 实例,而不是 Django 的 HttpRequest 实例。
  • 处理程序方法可能会返回 REST framework 的 Response,而不是 Django 的 HttpResponse。该视图将管理内容协商并在响应中设置正确的渲染器。
  • 任何 APIException 异常都会被捕获并调解为适当的响应。
  • 传入的请求将被认证,并且在将请求分派给处理程序方法之前将运行适当的权限或限流检查。

Django Rest Framework:进一步理解序列化之基于函数的视图

二,使用基于类的视图

使用 API​​View 类与使用常规 View 类几乎是一样的,像往常一样,传入的请求被分派到适当的处理程序方法,如 .get() 或 .post() 。另外,可以在控制 API 策略的各个方面的类上设置多个属性。

使用简例:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from django.contrib.auth.models import User

class ListUsers(APIView):
    """
    查看以列出系统中的所有用户。

    * 需要令牌认证。
    * 只有管​​理员用户才能访问此视图。
    """
    authentication_classes = (authentication.TokenAuthentication,)
    permission_classes = (permissions.IsAdminUser,)

    def get(self, request, format=None):
        """
        以列表格式返回所有用户。
        """
        usernames = [user.username for user in User.objects.all()] # 这是一个列表推导式
        return Response(usernames)

1,重构为基于类的视图

from django.http import HttpResponse, JsonResponse, Http404
from snippet.models import Snippet
from snippet.serializers import SnippetSerializer
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView

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)

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)
  • 必须继承APIView类。
  • 具体序列化器的使用逻辑上与函数视图没什么区别,但对不同的 HTTP 方法有更好的分离。

2,重构路由

from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    url(r'^snippet/$', views.SnippetList.as_view()),
    url(r'^snippet/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)
  • 与基于函数视图的url不同的是,基于类视图的url使用"序列化类名.as_view()方法"实现路由功能。

3,运行

在这里插入图片描述
结果与基于函数的视图一样。

三,通用视图

1,什么是通用视图

基于类的视图的一个关键好处是,它允许组合一些可重用行为。REST framework 利用这一点,通过提供许多预构建的视图即通用视图来提供常用模式,它们允许快速构建紧密映射到数据库模型的 API 视图。

如果通用视图不适合 API 需求,则可以使用常规 APIView 类自定义处理逻辑,或者重用通用视图使用的 mixins 类和基类来组成自己的可重用通用视图集。

通常,在使用通用视图时将重写视图,并设置几个类属性:
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAdminUser,)

对于更复杂的情况,还能重写视图类中的各种方法:
class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAdminUser,)

    def list(self, request):
        # Note the use of `get_queryset()` instead of `self.queryset`
        queryset = self.get_queryset()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

2,API 参考 (API Reference)

参考官方API Reference或 另一篇:Django Rest Framework:通用视图API Reference与视图集

四,使用mixins减少代码量

使用基于类的视图的优势之一是可以很容易撰写可重复使用的行为。

The create/retrieve/update/delete operations that we’ve been using so far are going to be pretty similar for any model-backed API views we create. Those bits of common behaviour are implemented in REST framework’s mixin classes.

到目前为止,我们一直在使用的create / retrieve / update / delete操作对于已经创建的任何模型支持的API视图非常相似。 这些常见行为在REST框架的mixin类中实现。

1,重构SnippetList

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)
  • 使用 GenericAPIView 构建了视图,并且用上 ListModelMixin 和 CreateModelMixin提供核心功能,用 mixin类提供.list()和.create()操作。
  • 将 get 和 post 方法绑定到适当的操作。

2,重构SnippetDetail

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)
  • 再次使用 GenericAPIView 类来提供核心功能,并添加 mixins 来提供 .retrieve(),.update() 和 .destroy() 操作。

3,运行

在这里插入图片描述

五,使用通用的基于类的视图进一步减少代码量

REST framework 提供了一套已经混合的通用视图。

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

猜你喜欢

转载自blog.csdn.net/dangfulin/article/details/108178415