文章目录
- 零、视图家族
- 一、GenericAPIView:视图家族的基类
- 二、Mixins:视图工具集
- 1.群查
- 查看源码
- 代码实现
- 测试接口
- 2.单查
- 查看源码
- 代码实现
- 测试接口
- 3.单增
- 查看源码
- 代码实现
- 测试接口
- 4.单改
- 查看源码
- 代码实现
- 测试接口
零、视图家族
Django REST framework 为了方便视图类的操作,构建了包括以下几种视图类和工具集:
- views:API视图
- generics:工具视图
- mixins:视图工具集
- viewsets:视图集
一、GenericAPIView:视图家族的基类
generics.py 中的 GenericAPIView 作为视图家族中重要的基类,在后面的接口代码的实现中起到重要作用。
用 Pycharm 可以看到 GenericAPIView 的方法和继承关系:
GenericAPIView 继承自 APIView,使用兼容 APIView,也就是说依旧可以使用 get,post等方法。
但是,这里 GenericAPIView 封装了更多有趣的方法。
- get_queryset(): 从类属性 queryset 中获得 model 的 queryset 数据
- get_object(): 通过有名分组 pk 确定唯一操作对象
自定义主键的有名分组 :lookup_field = ‘id’ - get_serializer():从类属性 serializer_class 中获得serializer 的序列化类
二、Mixins:视图工具集
mixins.py
:视图工具集,用来辅助 GenericAPIView
包含有五个工具类文件,六个工具类方法:
- CreateModeMixin:
- **单增:**create
- ListModelMixin:
- **群查:**list
- RetrieveModelMixin:
- **单查:**retrieve
- UpdateModelMixin:
- **单整体改:**update
- **单局部改:**partial_update
- DestroyModelMixin:
- **单删:**destroy,一般不使用该方法,或重写方法利用字段is_delete 来实现删除操作。
1.群查
查看源码
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()),
]
测试接口
2.单查
查看源码
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)
测试接口
3.单增
查看源码
查看 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)
测试接口
4.单改
查看源码
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)
测试接口
修改成功