Django

django rest framework通用view

2018-11-07  本文已影响0人  程序员同行者

官方文档:http://www.django-rest-framework.org/
drf为我们提供强大的通用view的功能,本博客对这些view进行简要的总结分析。
首先,我们看一下主要的几种view以及他们之间的关系。

image
这其中,还涉及了mixins,主要也分为5类:
image

下面我们以课程(course)作为一个例子,对view进行一个总结。

1. django View

首先,我们使用django自带的view,获取一个课程的列表:

# drf是通过json的格式进行数据交互的,所以这里也返回json数据
import json
from django.views.generic.base import View
from django.core import serializers
from django.http import HttpResponse,JsonResponse
from .models import Course

class CourseListView(View):
    def get(self, request):
        """
        通过django的view实现课程列表页
        """
        courses = Course.objects.all()[:10]
        json_data = serializers.serialize('json', courses)
        json_data = json.loads(json_data)
        return JsonResponse(json_data, safe=False)

2. APIView

接下来,我们用APIView来实现

from rest_framework.views import APIView
from rest_framework.response import Response
# 这个serializers是在其他文件自定义的,这里对这个不进行过多介绍
from .serializers import CourseSerializer

class CourseListView(APIView):
    def get(self, request, format=None):
        """
        通过APIView实现课程列表页
        """
        courses = Course.objects.all()
        serializer = CourseSerializer(courses, many=True)
        return Response(serializer.data)

在APIView这个例子中,调用了drf本身的serializer以及Response方法。
  APIView对django本身的View进行封装,从上述的代码,这样分析,两者的差别看起来不是很大,但实际中APIView做了很多东西,它定义了很多属性与方法,举几个例子

# 这三个是常用的属性
    authentication_classes : 用户登录认证方式,session或者token等等
    permission_classes : 权限设置,是否需要登录等
    throttle_classes : 限速设置,对用户进行一定的访问次数限制等等。

到这里,可能还不能体现drf通过view的强大之处,那么接下来的GenericAPIView就展示了它强大的功能。

3. GenericAPIView

from rest_framework import mixins
from rest_framework import generics
class CourseListView(mixins.ListModelMixin, generics.GenericAPIView):
    """
    课程列表页
    """
    queryset = Course.objects.all()
    serialize_class = CourseSerializer
    def get(self, request, *args, **kwargs):
    # list方法是存在于mixins中的,同理,create等等也是
    # GenericAPIView没有这些方法!
        return self.list(request, *args, **kwargs)

在这个例子中,继承了mixins中的ListModelMixin,在get( )方法中,调用了它的list( )方法,list方法会返回queryset的json数据。这里对mixins不进行过多的介绍。
GenericAPIView对APIView再次封装,实现了强大功能:

举个例子,获取具体的某个课程,假设传进来的ulr为:http://127.0.0.1:8000/course/1/,系统会默认这个1指的是course的id。那么,现在面临一个问题,假设我定义了一个用户收藏的model,我想要知道我id为1的课程是否收藏了,我传进来的url为:http://127.0.0.1:8000/userfav/1/,系统会默认获取userfav的id=1的实例,这个逻辑明显是错的,我们需要获取course的id=1的收藏记录,所以我们就需要用到这个属性或者重载这个方法 lookup_field=”course_id”.

在generics除了GenericAPIView还包括了其他几个View: CreateAPIView、ListAPIView、RetrieveAPIView、ListCreateAPIView···等等,其实他们都只是继承了相应一个或多个mixins和GenericAPIView,这样,有什么好处?我们看一下同样一个例子的代码:

class CourseListView(ListAPIView):
    """
    课程列表页
    """
    queryset = Course.objects.all()
    serialize_class = CourseSerializer

这样,就完成了和刚刚一模一样的功能!

4.GenericViewSet

首先,我们思考一个问题,同样上面的例子,我们在功能上,要获取课程的列表,也要获取某个课程的具体信息。那么怎么实现,按照GenericAPIView,我们可以这样实现:

class CourseView(ListAPIView,RetrieveAPIView):
    # 只需要在上面的基础上,再继承RetrieveAPIView就ok了。
    queryset = Course.objects.all()
    serialize_class = CourseSerializer

但这样实现有一个问题,关于serialize_class,显然,当获取课程列表时,只需要传回去所有课程的简要信息,如课程名字,老师,封面等等,但当获取课程的具体信息,我们还要将他们的章节以及相关下载资料(很明显,章节是另外一个model,有一个外键指向course),这些信息会很多,在获取课程列表,将这些传回去显然是不理智的。那么,还需要再定义一个CourseDetailSerializer,在get /courses/的时候,使用CourseSerializer,在get /courses/id/的时候,使用CourseDetailSerializer。
  那么,问题来了,我们怎么获取到是哪个action方法?这个时候,viewset就出场了!

from rest_framework import viewsets
import...
class CourseViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    queryset = Course.objects.all()

    def get_serializer_class(self):
    # 重写get_serializer_class方法
        if self.action == 'list':
            return CourseSerializer
        return CourseDetailSerializer

# 进行绑定
courses = CourseViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
urlpatterns = [
    ...
    # 常规加入url匹配项
    url(r'courses/', CourseViewSet.as_view(), name='courses'),]

这样,我们就将http请求方法与mixins方法进行了关联。那么还有更简洁的方法吗?很明显,当然有,这个时候,route就登场了!

class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    # 满足只有GET方法请求的情景
    pass

class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    # 满足所有请求都有的情景
    pass

到这里,ViewSet的强大功能就介绍完了,强烈建议在做drf的时候,使用ViewSet与mixins方法结合进行开发,为我这种小白开发者提供了很强大完整的功能!

上一篇 下一篇

猜你喜欢

热点阅读