Django REST framework 为了方便视图类的操作,构建了包括以下几种视图类和工具集:
generics.py 中的 GenericAPIView 作为视图家族中重要的基类,在后面的接口代码的实现中起到重要作用。
用 Pycharm 可以看到 GenericAPIView 的方法和继承关系:
GenericAPIView 继承自 APIView,使用兼容 APIView,也就是说依旧可以使用 get,post等方法。
但是,这里 GenericAPIView 封装了更多有趣的方法。
mixins.py
:视图工具集,用来辅助 GenericAPIView
包含有五个工具类文件,六个工具类方法:
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
# get_queryset 通过子类继承 GenericAPIView 得到
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)
继承工具类可以简化请求函数的实现体,但是必须继承 GenericAPIView,因为需要 GenericAPIView 提供类属性和方法。
工具类方法返回值是 Response 对象,可以用 response.data 拿到,扔给之前封装的APIResponse 类实现格式。
views.py
class BookListGenericAPIView(ListModelMixin, GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BookModelSerializer
def get(self, request, *args, **kwargs):
# 调用 ListModelMixin 的 list方法
response = self.list(request, *args, **kwargs)
# 添加自己封装的 APIResponse
return APIResponse(results=response.data)
urls.py
from django.conf.urls import url
from api import views
urlpatterns = [
url(r'^v3/books/$', views.BookListGenericAPIView.as_view()),
url(r'^v3/books/(?P<pk>.*)/$', views.BookListGenericAPIView.as_view()),
]
class RetrieveModelMixin:
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
class BookListGenericAPIView(ListModelMixin, RetrieveModelMixin, GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BookModelSerializer
def get(self, request, *args, **kwargs):
if 'pk' in kwargs:
response = self.retrieve(request, *args, **kwargs)
else:
response = self.list(request, *args, **kwargs)
return APIResponse(results=response.data)
查看 CreateModelMixin
源码
class CreateModelMixin:
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
# 序列化
serializer = self.get_serializer(data=request.data)
# 验证
serializer.is_valid(raise_exception=True)
# 表单数据重建,函数名有语义,而直接调用逻辑是无意义的
self.perform_create(serializer)
# 设置 header
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
可以看到这个类就是把之前单增的方法封装在一起方便调用
class BookListGenericAPIView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BookModelSerializer
def post(self, request, *args, **kwargs):
response = self.create(request, *args, **kwargs)
return APIResponse(results=response.data)
class UpdateModelMixin:
"""
Update a model instance.
"""
# 实现单整体改
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
# 单局部改,调用 update 设置 partial = True
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
class BookListGenericAPIView(ListModelMixin, UpdateModelMixin, GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BookModelSerializer
def put(self, request, *args, **kwargs):
response = self.update(request, *args, **kwargs)
return APIResponse(results=response.data)
def patch(self, request, *args, **kwargs):
response = self.partial_update(request, *args, **kwargs)
return APIResponse(results=response.data)
修改成功