Django框架(二十三)-- Django rest_framework-视图组件
一、基本视图
class PublishView(APIView): def get(self, request): publish_list = Publish.objects.all() bs = PublishSerializers(publish_list, many=True) return JsonResponse(bs.data,safe=False) def post(self, request): # 添加一条数据 print(request.data) bs = PublishSerializers(data=request.data) if bs.is_valid(): bs.save() # 生成记录 return JsonResponse(bs.data,safe=False) else: return JsonResponse(bs.errors,safe=False) class PublishDetailView(APIView): def get(self, request, pk): publish_obj = Publish.objects.filter(pk=pk).first() bs = PublishSerializers(publish_obj, many=False) return JsonResponse(bs.data,safe=False) def put(self, request, pk): publish_obj = Publish.objects.filter(pk=pk).first() bs = PublishSerializers(data=request.data, instance=publish_obj) if bs.is_valid(): bs.save() # update return JsonResponse(bs.data) else: return JsonResponse(bs.errors) def delete(self, request, pk): Publish.objects.filter(pk=pk).delete() return JsonResponse("")
二、自定义的封装视图
class Create: def create(self,request): bs = serializers(data=request.data) if bs.is_valid(): bs.save() # 生成记录 return JsonResponse(bs.data,safe=False) else: return JsonResponse(bs.errors,safe=False) class List: def list(self,request): queryset = self.queryset bs = self.serializers(queryset, many=True) return JsonResponse(bs.data,safe=False) # 将create和 list方法抽出来,封装起来 class PublishView(APIView,List,Create): queryset=Publish.objects.all() serializers=PublishSerializers def get(self, request): return self.list(request) def post(self, request): return self.create(request) class BookView(APIView,List,Create): queryset=Book.objects.all() serializers=BookSerializer def get(self, request): return self.list(request) def post(self, request): return self.create(request)
三、利用mixin类和generice类编写视图
1、使用
# ListModelMixin 查询所有; CreateModelMixin:创建数据; RetrieveModelMixin:查询一条; UpdateModelMixin:更新数据; DestroyModelMixin:删除数据 from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin from rest_framework.generics import GenericAPIView class PublishView(GenericAPIView,ListModelMixin,CreateModelMixin): queryset = Publish.objects.all() serializer_class = PublishSerializers def get(self, request): # self.list(request),ListModelMixin类中的函数属性 return self.list(request) def post(self, request): return self.create(request) class BookView(GenericAPIView,ListModelMixin,CreateModelMixin): queryset = Book.objects.all() serializer_class = BookSerializers def get(self, request): return self.list(request) def post(self, request): return self.create(request)
2、源码
(1)ListModelMixin类
class ListModelMixin(object): def list(self, request, *args, **kwargs): # 获取queryset对象,filter_queryset是利用过滤条件过滤 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)
(2)self.get_queryset()与self.get_serializer()
# self.get_queryset() # 先自身找,然后类中找,再去父类GenericAPIView中找,找到 def get_queryset(self): # queryset在GenericAPIView设默认值为None,因此要重新定义queryset,指定queryset对象 queryset = self.queryset if isinstance(queryset, QuerySet): # 查询所有数据 queryset = queryset.all() return queryset
# self.get_serializer() # 先自身找,然后类中找,再去父类GenericAPIView中找,找到 def get_serializer(self, *args, **kwargs): # get_serializer_class()返回的是serializer_class,默认值为None,所以要重新定义返回的是serializer_class serializer_class = self.get_serializer_class() kwargs['context'] = self.get_serializer_context() return serializer_class(*args, **kwargs)
(3)CreateModelMixin类下的create
class CreateModelMixin(object): 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()
(4)UpdateModelMixin类下的update
class UpdateModelMixin(object): def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) # get_object 返回的是一个普通对象 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): instance._prefetched_objects_cache = {} return Response(serializer.data) def perform_update(self, serializer): serializer.save()
(5)DestroyModelMixin类下的destroy
class DestroyModelMixin(object): def destroy(self, request, *args, **kwargs): # get_object 返回的是一个普通对象 instance = self.get_object() self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) def perform_destroy(self, instance): instance.delete()
(6)RetrieveModelMixin类下的retrieve
class RetrieveModelMixin(object): # def retrieve(self, request, *args, **kwargs): # get_object 返回的是一个普通对象 instance = self.get_object() serializer = self.get_serializer(instance) return Response(serializer.data)
四、利用generics 下的ListCreateAPIView,RetrieveUpdateDestroyAPIView
1、使用
from rest_framework.generics import ListCreateAPIView, ListAPIView, RetrieveUpdateDestroyAPIView # 继承了ListCreateAPIView类,而ListCreateAPIView又继承了多个类,并且定义了get和post方法,因此,只需要重定义queryset和serializer_class即可 class PublishView(ListCreateAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializers class PublishDetailView(RetrieveUpdateDestroyAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializers
2、源码
# 继承了多个类,类中的方法也是调用了GenericAPIView类中的list、create函数属性 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)
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)
五、使用ModelViewSet(不建议使用)
1、使用
# 路由层 url(r'^publish', views.PublishView.as_view({'get': 'list', 'post': 'create'})), url(r'^publish/(?P<pk>\d+)', views.PublishView.as_view({'get': 'retrieve', 'put': 'update','delete':'destroy'})), # 视图层 from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer class PublishView(ModelViewSet): queryset = Publish.objects.all() serializer_class = PublishSerializers
2、源码
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): pass class GenericViewSet(ViewSetMixin, generics.GenericAPIView): pass # ViewSetMixin是一个魔法类,重写了as_view方法,所以继承该类的时候,一般放前面,否则会调用APIView的as_view方法 class ViewSetMixin(object): """ This is the magic. view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) """ @classonlymethod def as_view(cls, actions=None, **initkwargs): cls.name = None cls.description = None cls.suffix = None cls.detail = None cls.basename = None def view(request, *args, **kwargs): self = cls(**initkwargs) # actions ---> {'get': 'list', 'post': 'create'} self.action_map = actions for method, action in actions.items(): handler = getattr(self, action) # 将list方法的地址赋给get,create方法的地址赋给post # 将list绑定给GET,create绑定给POST setattr(self, method, handler) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs # And continue as usual return self.dispatch(request, *args, **kwargs) # take name and docstring from class update_wrapper(view, cls, updated=()) update_wrapper(view, cls.dispatch, assigned=()) view.cls = cls view.initkwargs = initkwargs view.actions = actions return csrf_exempt(view)
六、强调:ViewSetMixin魔法类
- ViewSetMixin类重写了
as_view
方法,因此为了调用它的as_view方法,在继承的时候,要写在APIView前面
class TestAll(ViewSetMixin,APIView): pass
- ViewSetMixin 类可以实现全部视图函数写在一个类中
# 路由层 [ url(r'^test1/$', views.TestAll.as_view({'get': 'test'})), # 将test视图函数赋给get url(r'^test2/$', views.TestAll.as_view({'get': 'test2'})), url(r'^test3/$', views.TestAll.as_view({'get': 'test3'})) ] # 视图层 class TestAll(ViewSetMixin,APIView): def test(self,request): return HttpResponse('test') def test2(self, request): return HttpResponse('test2') def test3(self, request): return HttpResponse('test3')