继承APIView的子类

    修改之前项目中的,去掉show_subjects视图函数,添加一个名为SubjectView的类,该类继承自ListAPIViewListAPIView能接收GET请求,它封装了获取数据列表并返回JSON数据的get方法。ListAPIViewAPIView 的子类,APIView还有很多的子类,例如CreateAPIView可以支持POST请求,UpdateAPIView可以支持PUT和PATCH请求,DestoryAPIView可以支持DELETE请求。SubjectView 的代码如下所示。

    刚才说过,由于SubjectView的父类ListAPIView已经实现了get方法来处理获取学科列表的GET请求,所以我们只需要声明如何获取学科数据以及如何序列化学科数据,前者用queryset属性指定,后者用serializer_class属性指定。要使用上面的SubjectView,需要修改urls.py文件,如下所示。

    1. urlpatterns = [
    2. path('api/subjects/', SubjectView.as_view()),
    3. ]

    很显然,上面的做法较之之前讲到的FBV要简单很多。

    继承ModelViewSet

    1. from rest_framework.viewsets import ModelViewSet
    2. class SubjectViewSet(ModelViewSet):
    3. queryset = Subject.objects.all()

    通过查看ModelViewSet类的源代码可以发现,该类共有6个父类,其中前5个父类分别实现对POST(新增学科)、GET(获取指定学科)、PUT/PATCH(更新学科)、DELETE(删除学科)和GET(获取学科列表)操作的支持,对应的方法分别是createretrieveupdatedestroylist。由于ModelViewSet的父类中已经实现了这些方法,所以我们几乎没有编写任何代码就完成了学科数据全套接口的开发,我们要做的仅仅是指出如何获取到数据(通过queryset属性指定)以及如何序列化数据(通过serializer_class属性指定),这一点跟上面继承APIView的子类做法是一致的。

    要使用上面的SubjectViewSet,需要在urls.py文件中进行URL映射。由于ModelViewSet相当于是多个视图函数的汇总,所以不同于之前映射URL的方式,我们需要先创建一个路由器并通过它注册SubjectViewSet,然后将注册成功后生成的URL一并添加到urlspattern列表中,代码如下所示。

    1. from rest_framework.routers import DefaultRouter
    2. router = DefaultRouter()
    3. router.register('api/subjects', SubjectViewSet)
    4. urlpatterns += router.urls

    除了ModelViewSet类外,DRF还提供了一个名为ReadOnlyModelViewSet 的类,从名字上就可以看出,该类是只读视图的集合,也就意味着,继承该类定制的数据接口只能支持GET请求,也就是获取单个资源和资源列表的请求。

    1. REST_FRAMEWORK = {
    2. 'PAGE_SIZE': 10,
    3. 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination'
    4. }

    除了上面配置的PageNumberPagination分页器之外,DRF还提供了和CursorPagination分页器,值得一提的是CursorPagination,它可以避免使用页码分页时暴露网站的数据体量,有兴趣的读者可以自行了解。如果不希望使用配置文件中默认的分页设定,可以在视图类中添加一个pagination_class属性来重新指定分页器,通常可以将该属性指定为自定义的分页器,如下所示。

    1. class SubjectView(ListAPIView):
    2. # 指定如何获取数据
    3. queryset = Subject.objects.all()
    4. # 指定如何序列化数据
    5. # 指定如何分页
    6. pagination_class = CustomizedPagination

    如果不希望数据分页,可以将pagination_class属性设置为None来取消默认的分页器。

    如果希望使用CBV定制获取老师信息的数据接口,也可以通过继承ListAPIView来实现。但是因为要通过指定的学科来获取对应的老师信息,因此需要对老师数据进行筛选而不是直接获取所有老师的数据。如果想从请求中获取学科编号并通过学科编号对老师进行筛选,可以通过重写get_queryset方法来做到,代码如下所示。

    1. class TeacherView(ListAPIView):
    2. serializer_class = TeacherSerializer
    3. def get_queryset(self):
    4. queryset = Teacher.objects.defer('subject')
    5. try:
    6. sno = self.request.GET.get('sno', '')
    7. queryset = queryset.filter(subject__no=sno)
    8. return queryset
    9. except ValueError:
    10. raise Http404('No teachers found.')