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')

 

posted @ 2018-12-12 23:41  holy_pie  阅读(261)  评论(0编辑  收藏  举报