• 从django的序列化到rest-framework 序列化


    1.利用Django的view实现返回json数据

    from django.views.generic import View
    from goods.models import Goods
    
    class GoodsListView(View):
        def get(self,request):
            #通过django的view实现商品列表页
            json_list = []
            #获取所有商品
            goods = Goods.objects.all()
            for good in goods:
                json_dict = {}
                #获取商品的每个字段,键值对形式
                json_dict['name'] = good.name
                json_dict['category'] = good.category.name
                json_dict['market_price'] = good.market_price
                json_list.append(json_dict)
    
            from django.http import HttpResponse
            import json
            #返回json,一定要指定类型content_type='application/json'
            return HttpResponse(json.dumps(json_list),content_type='application/json')
    View Code

    2.django的serializer序列化model

    (1)model_to_dict

    当字段比较多时,一个字段一个字段的提取很麻烦,可以用model_to_dict,将model整个转化为dict

    from django.views.generic import View
    from goods.models import Goods
    
    class GoodsListView(View):
        def get(self,request):
            #通过django的view实现商品列表页
            json_list = []
            #获取所有商品
            goods = Goods.objects.all()
            # for good in goods:
            #     json_dict = {}
            #     #获取商品的每个字段,键值对形式
            #     json_dict['name'] = good.name
            #     json_dict['category'] = good.category.name
            #     json_dict['market_price'] = good.market_price
            #     json_list.append(json_dict)
    
            from django.forms.models import model_to_dict
            for good in goods:
                json_dict = model_to_dict(good)
                json_list.append(json_dict)
    
            from django.http import HttpResponse
            import json
            #返回json,一定要指定类型content_type='application/json'
            return HttpResponse(json.dumps(json_list),content_type='application/json')
    View Code
    但是这样有个问题,就是ImageField 和models.DateTimeField字段不能序列化

    如何才能将所有字段序列化呢?就要用到django的serializers

    (2)django serializer的用法

    from django.views.generic import View
    from goods.models import Goods
    
    class GoodsListView(View):
        def get(self,request):
            #通过django的view实现商品列表页
            json_list = []
            #获取所有商品
            goods = Goods.objects.all()
            # for good in goods:
            #     json_dict = {}
            #     #获取商品的每个字段,键值对形式
            #     json_dict['name'] = good.name
            #     json_dict['category'] = good.category.name
            #     json_dict['market_price'] = good.market_price
            #     json_list.append(json_dict)
    
            import json
            from django.core import serializers
            from django.http import JsonResponse
    
            json_data = serializers.serialize('json',goods)
            json_data = json.loads(json_data)
            #In order to allow non-dict objects to be serialized set the safe parameter to False.
            return JsonResponse(json_data,safe=False)
    View Code

    django的serializer虽然可以很简单实现序列化,但是有几个缺点

    • 字段序列化定死的,要想重组的话非常麻烦
    • 以上写了这么多只是为了引入django rest framework和简单介绍django的序列化用法,下面就是重点讲解django rest framework了
    
    

    APIview方式实现商品列表页

    配置rest_framework

    settings.py中添加

    INSTALLED_APPS = [
        'rest_framework',
    ]

    MxShop/urls.py

    urlpatterns = [
        path('api-auth/',include('rest_framework.urls')),
    ]
    新建serializers.py
    from rest_framework import serializers
    
    
    class GoodsSerializer(serializers.Serializer):
        name = serializers.CharField(required=True,max_length=100)
        click_num = serializers.IntegerField(default=0)
        goods_front_image = serializers.ImageField()
    View Code
    # googd/views.py
    
    from rest_framework.views import APIView
    from goods.serializers import GoodsSerializer
    from .models import Goods
    from rest_framework.response import Response
    
    
    class GoodsListView(APIView):
        '''
        商品列表
        '''
        def get(self,request,format=None):
            goods = Goods.objects.all()
            goods_serialzer = GoodsSerializer(goods,many=True)
            return Response(goods_serialzer.data)
    View Code

    一对多和多对多字段的序列化:

    class BookSerializers(serializers.Serializer):
        title = serializers.CharField(max_length=32)
        price = serializers.IntegerField()
        pub_date = serializers.DateField()
    
        publish = serializers.CharField(source="publish.email")  # 一对多字段使用source字段处理
    
        # 多对多使用下面字段,并且配一个方法,方法里面可自定义任意东西,可取作者表的名字。
        authors = serializers.SerializerMethodField()
    
        def get_authors(self, obj):
            temp = []
            for obj in obj.authors.all():
                temp.append(obj.name)
            return temp
    View Code

    序列化的过程:

    '''
    序列化BookSerializers(book_list,many=True)过程:
        temp=[]
        for obj in book_list:
            temp.append({
                "title":obj.title,
                "price":obj.price,
                "pub_date":obj.pub_date,
                #"publish":str(publish),
                "publish":obj.publish.name,
                "authors":get_authors(obj)
    
            })
    '''
    View Code

    drf的Modelserializer实现商品列表页

    上面是用Serializer实现的,需要自己手动添加字段,如果用Modelserializer,会更加的方便,直接用__all__就可以全部序列化

    from rest_framework import serializers
    from .models import Goods
    
    #Serializer实现商品列表页
    # class GoodsSerializer(serializers.Serializer):
    #     name = serializers.CharField(required=True,max_length=100)
    #     click_num = serializers.IntegerField(default=0)
    #     goods_front_image = serializers.ImageField()
    
    #ModelSerializer实现商品列表页
    class GoodsSerializer(serializers.ModelSerializer):
        class Meta:
            model = Goods
            fields = '__all__'
    View Code

    GenericView实现商品列表页

    1)mixins和generic一起用用

    GenericAPIView继承APIView,封装了很多方法,比APIView功能更强大

    class GenericAPIView(views.APIView):
        """
        Base class for all other generic views.
        """
        # You'll need to either set these attributes,
        # or override `get_queryset()`/`get_serializer_class()`.
        # If you are overriding a view method, it is important that you call
        # `get_queryset()` instead of accessing the `queryset` property directly,
        # as `queryset` will get evaluated only once, and those results are cached
        # for all subsequent requests.
        queryset = None
        serializer_class = None
    
        # If you want to use object lookups other than pk, set 'lookup_field'.
        # For more complex lookup requirements override `get_object()`.
        lookup_field = 'pk'
        lookup_url_kwarg = None
    
        # The filter backend classes to use for queryset filtering
        filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    
        # The style to use for queryset pagination.
        pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
    
        def get_queryset(self):
            """
            Get the list of items for this view.
            This must be an iterable, and may be a queryset.
            Defaults to using `self.queryset`.
    
            This method should always be used rather than accessing `self.queryset`
            directly, as `self.queryset` gets evaluated only once, and those results
            are cached for all subsequent requests.
    
            You may want to override this if you need to provide different
            querysets depending on the incoming request.
    
            (Eg. return a list of items that is specific to the user)
            """
            assert self.queryset is not None, (
                "'%s' should either include a `queryset` attribute, "
                "or override the `get_queryset()` method."
                % self.__class__.__name__
            )
    
            queryset = self.queryset
            if isinstance(queryset, QuerySet):
                # Ensure queryset is re-evaluated on each request.
                queryset = queryset.all()
            return queryset
    
        def get_object(self):
            """
            Returns the object the view is displaying.
    
            You may want to override this if you need to provide non-standard
            queryset lookups.  Eg if objects are referenced using multiple
            keyword arguments in the url conf.
            """
            queryset = self.filter_queryset(self.get_queryset())
    
            # Perform the lookup filtering.
            lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
    
            assert lookup_url_kwarg in self.kwargs, (
                'Expected view %s to be called with a URL keyword argument '
                'named "%s". Fix your URL conf, or set the `.lookup_field` '
                'attribute on the view correctly.' %
                (self.__class__.__name__, lookup_url_kwarg)
            )
    
            filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
            obj = get_object_or_404(queryset, **filter_kwargs)
    
            # May raise a permission denied
            self.check_object_permissions(self.request, obj)
    
            return obj
    
        def get_serializer(self, *args, **kwargs):
            """
            Return the serializer instance that should be used for validating and
            deserializing input, and for serializing output.
            """
            serializer_class = self.get_serializer_class()
            kwargs['context'] = self.get_serializer_context()
            return serializer_class(*args, **kwargs)
    
        def get_serializer_class(self):
            """
            Return the class to use for the serializer.
            Defaults to using `self.serializer_class`.
    
            You may want to override this if you need to provide different
            serializations depending on the incoming request.
    
            (Eg. admins get full serialization, others get basic serialization)
            """
            assert self.serializer_class is not None, (
                "'%s' should either include a `serializer_class` attribute, "
                "or override the `get_serializer_class()` method."
                % self.__class__.__name__
            )
    
            return self.serializer_class
    
        def get_serializer_context(self):
            """
            Extra context provided to the serializer class.
            """
            return {
                'request': self.request,
                'format': self.format_kwarg,
                'view': self
            }
    
        def filter_queryset(self, queryset):
            """
            Given a queryset, filter it with whichever filter backend is in use.
    
            You are unlikely to want to override this method, although you may need
            to call it either from a list view, or from a custom `get_object`
            method if you want to apply the configured filtering backend to the
            default queryset.
            """
            for backend in list(self.filter_backends):
                queryset = backend().filter_queryset(self.request, queryset, self)
            return queryset
    
        @property
        def paginator(self):
            """
            The paginator instance associated with the view, or `None`.
            """
            if not hasattr(self, '_paginator'):
                if self.pagination_class is None:
                    self._paginator = None
                else:
                    self._paginator = self.pagination_class()
            return self._paginator
    
        def paginate_queryset(self, queryset):
            """
            Return a single page of results, or `None` if pagination is disabled.
            """
            if self.paginator is None:
                return None
            return self.paginator.paginate_queryset(queryset, self.request, view=self)
    
        def get_paginated_response(self, data):
            """
            Return a paginated style `Response` object for the given output data.
            """
            assert self.paginator is not None
            return self.paginator.get_paginated_response(data)
    GenericAPIView源码
    用的时候需要定义queryset和serializer_class
    GenericAPIView里面默认为空
    • queryset = None
    • serializer_class = None

    ListModelMixin里面list方法帮我们做好了分页和序列化的工作,只要调用就好了

    实现如下:

    from goods.serializers import GoodsSerializer
    from .models import Goods
    from rest_framework.response import Response
    from rest_framework import mixins
    from rest_framework import generics
    
    
    class GoodsListView(mixins.ListModelMixin,generics.GenericAPIView):
        '商品列表页'
        queryset = Goods.objects.all()
        serializer_class = GoodsSerializer
    
        def get(self,request,*args,**kwargs):
            return self.list(request,*args,**kwargs)
    View Code

    上面的代码优化,可以直接继承ListAPIView,ListAPIView主要做了两件事:

    • ListAPIView(mixins.ListModelMixin,GenericAPIView)        继承了这两个类
    • 写好了get方法
    • 我们要获取商品列表页的信息,只要写三行代码就可以了
    • class GoodsListView(generics.ListAPIView):
          '商品列表页'
          queryset = Goods.objects.all()
          serializer_class = GoodsSerializer

      viewsets和router完成商品列表页

    • 主要用到viewsets中的GenericViewSet
    • ViewSets和Routers结合使用
    • from goods.views import GoodsListViewSet
      from rest_framework.routers import DefaultRouter
      
      router = DefaultRouter()
      
      #配置goods的url
      router.register(r'goods', GoodsListViewSet)
      
      urlpatterns = [
          #商品列表页
          url('^', include(router.urls)),
      ]
      复制代码
      url
      class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
          '商品列表页'
      
          # 分页
          pagination_class = GoodsPagination
          #这里必须要定义一个默认的排序,否则会报错
          queryset = Goods.objects.all().order_by('id')
          serializer_class = GoodsSerializer
      View

      drf的APIView、GenericView、viewsets和router的原理分析

    • genericViewSet 是最高的一层

      往下

      GenericViewSet(viewsets)     ----drf

        GenericAPIView                  ---drf

          APIView                        ---drf

            View            ----django

      这些view功能的不同,主要的是有mixin的存在

      mixins总共有五种:

        CreateModelMixin

        ListModelMixin

        UpdateModelMixin

        RetrieveModelMixin

        DestoryModelMixin

    以ListModelMixin为例:

    如果不继承ListModelMixin的话,就无法将get和商品的列表关联起来,另外还有其中的分页等等,都无法实现。

    还有其它几个mixin(增删改查局部),这些功能都是mixin做的

     我们一般都是用viewsets

    ViewSet类与View类其实几乎是相同的,但提供的是read或update这些操作,而不是get或put 等HTTP动作。同时,ViewSet为我们提供了默认的URL结构, 使得我们能更专注于API本身。

     Router提供了一种简单,快速,集成的方式来定义一系列的urls

  • 相关阅读:
    直接选择排序(C++模版技术实现)
    求素数
    快速排序(C++模版技术实现)
    堆排序(C++模版技术实现)
    简单链式二叉树(C++模版技术实现)
    归并排序(C++模版技术实现)
    求斐波那契数列的两种解法
    C++中改变setw(n)的对齐方式
    C中的64位整型
    Windows版GCC之TDMGCC 4.5.2
  • 原文地址:https://www.cnblogs.com/shangchunhong/p/9824204.html
Copyright © 2020-2023  润新知