Day 75 视图类/视图工具类/工具视图类/视图集
视图家族
视图类
APIView和GenericAPIView
GenericAPIView中比较重要的两个方法:
-
get_object
- 获取单查对象
-
get_serializer
- 获取单查对象的序列化
from rest_framework.generics import GenericAPIView
class CarGenericAPIView(GenericAPIView):
#
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializers.CarModelSerializer
lookup_url_kwarg = 'pk'
def get(self, request, *args, **kwargs):
car_obj = self.get_object()
car_ser = self.get_serializer(car_obj)
return APIResponse(results=car_ser.data)
GenericAPIView中query_set默认为None,需要自己进行赋值
注: models.Car.objects 是Manager对象,管理QuerySet
Mixins视图工具类
必须配合GenericAPIView类使用,将单查, 群查, 单增, 整体/局部单改, 单删留个接口封装成retrieve, list, create, update, partial_update, destroy六个方法
原因: 六个方法的实现体,调用的方法就是GenericAPIView提供的
-
ListModelMixin
群查功能源码
class ListModelMixin: """ List a queryset. """ def list(self, request, *args, **kwargs): 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)
-
RetrieveModelMixin
单查功能源码
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)
-
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) 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 {}
-
DestroyModelMixin
单删功能源码
class DestroyModelMixin: """ Destroy a model instance. """ def destroy(self, request, *args, **kwargs): instance = self.get_object() self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) def perform_destroy(self, instance): instance.delete()
-
UpdateModelMixin
整体或局部单改功能源码
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() def partial_update(self, request, *args, **kwargs): kwargs['partial'] = True return self.update(request, *args, **kwargs)
视图工具类的使用
from rest_framework.mixins import RetrieveModelMixin, ListModelMixin, CreateModelMixin class CarReadCreateGenericAPIView(ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericAPIView): queryset = models.Car.objects.filter(is_delete=False).all() serializer_class = serializers.CarModelSerializer lookup_url_kwarg = 'pk' # 群查 # """ def get(self, request, *args, **kwargs): # car_query = self.get_queryset() # car_ser = self.get_serializer(car_query, many=True) # return APIResponse(results=car_ser.data) return self.list(request, *args, **kwargs) # """ # 单查 """ def get(self, request, *args, **kwargs): # car_obj = self.get_object() # car_ser = self.get_serializer(car_obj) # return APIResponse(results=car_ser.data) response = self.retrieve(request, *args, **kwargs) return APIResponse(results=response.data) """ # 单增 def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
Generic工具视图类
工具视图类就是将不同种类的mixins与GenericAPIView进行组合,一共有9个类(九种组合)
(单查群查不能在一起)
只需要我们配置三个类属性即可: queryset, serializer_class, lookup_url_kwarg
-
CreateAPIView
class CreateAPIView(mixins.CreateModelMixin, GenericAPIView): def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
-
ListAPIView
class ListAPIView(mixins.ListModelMixin, GenericAPIView): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)
-
RetrieveAPIView
class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView): def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs)
-
DestroyAPIView
class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView): def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
-
UpdateAPIView
class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView): def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def patch(self, request, *args, **kwargs): return self.partial_update(request, *args, **kwargs)
-
ListCreateAPIView
class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
-
RetrieveUpdateAPIView
class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView): def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def patch(self, request, *args, **kwargs): return self.partial_update(request, *args, **kwargs)
-
RetrieveDestroyAPIView
class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView): def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
-
RetrieveUpdateDestroyAPIView
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView): def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def patch(self, request, *args, **kwargs): return self.partial_update(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
视图集
核心: 视图集都继承了 ViewSetMixin 类,该类重写了as_view方法,相比APIView的as_view方法,额外多出了参数actions(解决如单查群查能放在同一个类中的问题)
-
ViewSet
该分支满足的接口与资源Model类关系不是特别密切:登录接口, 短信验证码接口
-
GenericViewSet
该分支严格满足资源接口,与数据库进行交互
-
ModelViewSet
能满足六大接口,只需要提供两个类属性
-
ReadOnlyModelViewSet
只满足单查群查接口
视图集产生的问题
- 没有群增,群整体改,群局部改,群删四个接口
- 删除操作视图集默认走的detroy方法是将资源从数据库中删除,通常是做一个字段is_delete字段修改表示删除
- 响应的结构只有数据,没有数据状态码和状态信息
解决:
class CarModelViewSet(ModelViewSet):
queryset = models.Car.objects.filter(is_delete=False).all()
serializer_class = serializers.CarModelSerializer
# 分析:从实际开发角度分析不合理点
# 1)没有群增,群整体改,群局部改,群删四个接口
# 2)删除操作视图集默认走的destroy方法是将资源从数据库中删除,通常一个做字段is_delete字段修改表示删除
# 3)响应的结果只有数据,没有数据状态码和状态信息
# 解决1,
# 群整体改,群局部改,全删三个接口可以独立成三个方法
def many_update(self, request, *args, **kwargs):
request_data = request.data
try:
pks = []
for dic in request_data:
pk = dic.pop('pk')
pks.append(pk)
book_query = models.Car.objects.filter(is_delete=False, pk__in=pks).all()
if len(pks) != len(book_query):
raise Exception('pk对应的数据不存在')
except Exception as e:
return Response({'detail': '%s' % e}, status=400)
car_ser = self.get_serializer(instance=book_query, data=request_data, many=True)
car_ser.is_valid(raise_exception=True)
car_list = car_ser.save()
return APIResponse(results=self.get_serializer(car_list, many=True).data)
def many_partial_update(self, request, *args, **kwargs):
return APIResponse(msg='这个地方是群局部改,你会写!')
def many_destroy(self, request, *args, **kwargs):
return APIResponse(msg='这个地方是群删,你会写!')
# 群增与单增必须公用一个接口,都要走create方法 - 重写create方法,用逻辑进行拆分
def create(self, request, *args, **kwargs):
request_data = request.data
if isinstance(request_data, list):
car_ser = self.get_serializer(data=request_data, many=True)
car_ser.is_valid(raise_exception=True)
car_obj = car_ser.save()
return APIResponse(msg='群增成功', results=self.get_serializer(car_obj, many=True).data)
return super().create(request, *args, **kwargs)
# 解决2,destroy方法是完成is_delete字段值修改 - 重写destroy方法,自定义实现体
def destroy(self, request, *args, **kwargs):
car_obj = self.get_object()
car_obj.is_delete = True
car_obj.save()
return APIResponse(msg='删除成功')
# 解决3,让群查有状态码和状态信息 - 重写list方法
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
return APIResponse(results=response.data)