在之前的 view 中,我们使用了 APIView 编写处理数据的逻辑,如前文所讲 APIView 直接继承 View 是一个比较偏底层的类,尽管灵活但需要自己实现很多常用功能。DRF 中在 APIView 的基础上提供了一系列高级类来简化这些日常操作,比如: ListModelMixin, GenericAPIView 等。
见: https://www.django-rest-framework.org/tutorial/3-class-based-views/ Using mixins 章节。
Mixins:
mixin 类提供了 actions 用于实现基础的 view 功能。注意:这里的 action 方法并非 http handler 如:.get(), .post() 等, 而是 create,list, retrieb,update, desdory 这样的方式是具体的实现更加灵活。
GenericAPIView:
这个类继承了 APIView,并在此基础上实现了基础的 list 和 detail views。在使用 GenericAPIView 时,通常都是与 minxin 类组合使用,比如 ListAPIView 同时继承了 ListModelMixin 和 GenericAPIView(见后面例子)。
在 generics 库中,通常也都是这样的搭配,即:一个 XXXModelMixin + GenericAPIView。 其中GenericAPIView 负责数据部分,比如 queryset 和 serializer,包括 Pagination 等。 ModelMixin 则控制着如何 handle 这些数据 如: list,create, update 等。 通过两个类的互补来实现了一些特定功能。
类属性:
- queryset - 用于返回 view 数据库中需要的对象。
- serializer_class - 用于做验证,反序列化 Input,序列化 Output。
- lookup_field - 搜索字段
- lokup_url_kwarg - tbd
分页:
- pagination_class - 自定义分页
过滤:
- filter_backend - 用于过滤 queryset
详见 https://www.django-rest-framework.org/api-guide/generic-views/#genericapiview
ListModelMixin 例子(ModelMixin 系列中的一个):
该类 提供 .list(request, *args, **kwargs) 方法,来实现列出 queryset。如果 queryset 返回 http 结果 200 OK, 表示有数据,则该数据生成的列表可以用分页方法进行个性化显示。
详见: https://www.django-rest-framework.org/api-guide/generic-views/#listmodelmixin
1 from products.serializers import ProductSerializer 2 from products.models import Product 3 from rest_framework import mixins 4 from rest_framework import generics 5 6 class ProductListView(mixins.ListModelMixin, generics.GenericAPIView): 7 """注意:与 APIView 不同的是, queryset 和 serializer 都已经包含在 GenericAPIView 中了,所以在此无需自行做代码实现 """ 8 queryset = Product.objects.all() 9 serializer_class = ProductSerializer 10 11 def get(self, request, *args, **kwargs): 12 return self.list(request, *args, **kwargs) # ListModelMixin 中包括 list 方法,该方法返回 queryset 作为 response 的body 13 14 def post(self, request, *args, **kwargs): 15 return self.create(request, *args, **kwargs)
如果 ProductListView 不需要提供 post 功能,该类可以更简单地通过 ListAPIView 来实现,具体如下:
1 class ProductListView(generics.ListAPIView): 2 # 省略如下代码 3 # def get(self, request, *args, **kwargs): 4 # return self.list(request, *args, **kwargs) 5 6 queryset = Product.objects.all() 7 serializer_class = ProductSerializer
经查阅源码,ListAPIView 的实现其实与第一个例子的逻辑几乎一模一样,只是少了 post 函数,因为 ListAPIView 的功能仅限于展示数据,而并非对数据进行增加或改动。
ListAPIView extra 知识点:
ListAPIView 一般用于在页面上列出所有对象详细信息,这个数据量有可能会相对庞大一些,所以需要考虑在此对输出页面进行分页配置。
在 DRF 中可以通过 setting.py 一个配置来完成分页这个复杂的功能。
见: https://www.django-rest-framework.org/api-guide/pagination/ Pagination 部分
在 setting 文件中末尾添加:
1 REST_FRAMEWORK = { 2 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 3 'PAGE_SIZE': 10 4 }
这样就会对结果进行自动分页且每页只显示 10 个数据对象
如果目前的 Pagination 功能还不满足项目需要,可更深度地自定制分页功能。详见 Modify the pagination style 部分。
通过修改 view.py 文件
1 from rest_framework.pagination import PageNumberPagination 2 3 # 设置个性化分页功能 4 class ProductPagination(PageNumberPagination): 5 page_size = 10 6 page_size_query_param = 'page_size' 7 page_query_param = 'p' # http://127.0.0.1:8000/product/?p=1 改为了 p 而不是原来的 page 8 max_page_size = 100 9 10 class ProductListView(generics.ListAPIView): 11 queryset = Product.objects.all() 12 serializer_class = ProductSerializer 13 pagination_class = ProductPagination # 指向个性化分页配置类
注:完成以上配置后,则不需要另外对 setting 文件中的 REST_FRAMEWORK 参数进行设置。