zoukankan      html  css  js  c++  java
  • 【DRF框架】序列化组件

    DRF框架的序列化组件

      在前后端分离的应用模式中,后端仅返回前端所需的数据,返回的数据类似是JSON,因此需要使用序列化组件进行序列化再将数据返回

     

    使用JsonResponse做序列化

    #  使用JsonResponse做序列化
    class  SearchBook(View):
        def  get(self, request):
    
            book_queryset = Book.objects.values('id', 'title', 'category', 'pub_time', 'publisher')
            book_list = list(book_queryset)
            for  book  in  book_list:
                      #  将publisher转化为字典格式
                    publisher_obj = Publisher.objects.filter(id=book['publisher']).first()
                    book['publisher'] = {
                        'id': publisher_obj.id,
                        'title': publisher_obj.title
                    }
                  #  JsonResponse序列化列表,需要加safe=False,json_dumps_params={'ensure_ascii':False}处理编码问题
                ret = JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii': False})     
                return HttpResponse(ret)

     

    使用django进行序列化

    #  使用Django自带的serializers做序列化
    from django.core.serializers import serialize
    
    
    class  SearchBook1(View):
        def  get(self, request):
        
                book_queryset = Book.objects.all()
                  #  使用serialize进行序列化
                ret = serialize('json', book_queryset, ensure_ascii=False)   #  ensure_ascii=False处理编码问题
                return HttpResponse(ret)

     

    使用DRF框架的准备

    1.导入模块

    from rest_framework.response import Response
    from rest_framework.views import APIView

      

    2.注册rest_framework

    # settings.py
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'SerDemo.apps.SerdemoConfig',
        'rest_framework'            # 注册rest_framework
    ]

     

    DRF框架的APIView

    所有的类都继承了APIView

    1.APIView继承了View

    2.豁免了csrf

    3.重新封装了request

    4.request新的属性

    request._request == View.request

    request.query_params == View.request.GET

    request.data == request.POST/PUT (除了GET请求的其他请求)

     

     

    使用序列化组件前的准备

    # models.py
    class Book(models.Model):
        title = models.CharField(max_length=32)
        CHOICES = ((1,"python"),(2,"linux"),(3,"go"))
        category = models.IntegerField(choices=CHOICES)
        pub_time = models.DateField()
        publisher = models.ForeignKey(to='Publisher')
        authors = models.ManyToManyField(to="Author")
    
        class Meta:
            verbose_name = '图书'                     # 模型类的名字
            verbose_name_plural = verbose_name       # 模型复数形式的名字
    
        def __str__(self):
            return self.title
    
    class Publisher(models.Model):
        title = models.CharField(max_length=32)
    
        class Meta:
            verbose_name = '出版社'
            verbose_name_plural = verbose_name
    
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
    
        class Meta:
            verbose_name = '作者'
            verbose_name_plural = verbose_name

     

    序列化组件

    '''
    根据模型构建序列化器
    '''
    # serializers.py
    from rest_framework import serializers   # 导入框架的序列化器
    
    
    # 外键字段的序列化器
    class PublisherSerializer(serializers.Serializer):
        # 根据外键模型的字段定义字段进行匹配
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
    
    # 多对多字段的序列化器
    class AuthorSerializer(serializers.Serializer):
        # 根据多对多字段模型的字段定义字段进行匹配
        id = serializers.IntegerField()
        name = serializers.CharField(max_length=32)
    
    
    class BookSerializer(serializers.Serializer):
        # 定义模型中需要序列化的字段,匹配的上的进行序列化,匹配不上的丢弃
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
        category = serializers.CharField(source='get_category_display')     # source通过ORM操作获得CHOICES的值
        pub_time = serializers.DateField()
    
        # 外键字段,先声明外键字段的序列化器再实例化
        publisher = PublisherSerializer()
    
        # 多对多字段,先声明多对多字段的序列化器再实例化
        authors = AuthorSerializer(many=True)       # 多个模型对象使用many=True

     

    正序列化(GET请求)

    1.声明序列化器

    2.将每个模型对象放到序列化器进行序列化化,多个对象必须指定many=True

    3.序列化器进行字段匹配,匹配上的进行序列化,匹配不上的丢弃,且必须满足序列化的所有字段要求

    4.序列化后返回序列化对象

    5.数据都在序列化对象.data

    6.通过Response返回

    class Search_book(APIView):
        # 查询数据,GET请求
        def get(self,request):
            book_queryset = Book.objects.all()
    
            # 使用序列化器进行序列化,返回序列化对象
            ser_obj = BookSerializer(book_queryset,many=True)    # 多个queryset对象使用many=True
    
            # 返回数据
            return Response(ser_obj.data)           # 序列化好的数据都在 序列化对象.data

     

    序列化组件的方法

      反序列化不验证:required=False
      仅在正序列化验证:read_only=True
      仅在反序列化验证:write_only=True
      序列化多个对象:many=True

     

    反序列化(POST请求)

    1.序列化器对校验字段进行过滤

    2.获取前端的数据,传入到序列化器,返回序列化器对象

    3.对序列化器进行校验,不通过返回错误信息

    4.校验通过调用save()方法,其内部会调用create()方法

    5.序列化器自定义create()方法新增模型对象并返回

    6.通过Response返回数据

    '''
    根据模型构建序列化器
    '''
    # serializers.py
    from rest_framework import serializers   # 导入框架的序列化器
    from SerDemo.models import Book
    
    
    # 外键字段的序列化器
    class PublisherSerializer(serializers.Serializer):
        # 根据外键模型的字段定义字段进行匹配
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
    
    # 多对多字段的序列化器
    class AuthorSerializer(serializers.Serializer):
        # 根据多对多字段模型的字段定义字段进行匹配
        id = serializers.IntegerField()
        name = serializers.CharField(max_length=32)
    
    
    class BookSerializer(serializers.Serializer):
        # 定义模型中需要序列化的字段,匹配的上的进行序列化,匹配不上的丢弃
        id = serializers.IntegerField(required=False)           # 反序列化不匹配该字段
        title = serializers.CharField(max_length=32)
        category = serializers.CharField(source='get_category_display',read_only=True)     # source通过ORM操作获得CHOICES的值
        category_post = serializers.IntegerField(write_only=True)                          # 用于反序列化的字段
        pub_time = serializers.DateField()
    
        # 外键字段,先声明外键字段的序列化器再实例化
        publisher = PublisherSerializer(read_only=True)             # 仅在正序列化匹配该字段
        publisher_id = serializers.IntegerField(write_only=True)    # 仅在反序列化匹配该字段
    
        # 多对多字段,先声明多对多字段的序列化器再实例化
        authors = AuthorSerializer(read_only=True,many=True)       # 多个模型对象使用many=True,正序列化匹配该字段
        authors_list = serializers.ListField(write_only=True)      # 反序列化匹配该字段
    
        # 新增对象调用create方法
        def create(self, validated_data):
            # validated_data 是数据的字典
    
            # 创建对象
            book_obj = Book.objects.create(
                title=validated_data.get('title'),
                category=validated_data.get('category_post'),
                pub_time = validated_data.get('pub_time'),
                publisher_id = validated_data.get('publisher_id'),
            )
            book_obj.authors.add(*validated_data['authors_list'])       # 多对多字段使用add
            book_obj.save()
            return book_obj
    # 新增数据,POST请求
        def post(self,request):
    
            # 对提交的数据进行反序列化,返回一个序列化对象
            ser_obj = BookSerializer(data=request.data)
    
            # 对序列化对象进行校验
            if ser_obj.is_valid():
                # 校验通过,新增数据
                ser_obj.save()      # 调用序列化器的create()方法
                return Response(ser_obj.data)  # 返回新增的数据
    
            else:
                # 校验不通过
                return Response(ser_obj.errors)

    源码流程

    # 2.1、开始初始化,执行PubliserView.as_view()
    class APIView(View):
        @classmethod
        def as_view(cls, **initkwargs):
            # 1.2、开始调用父类的as_view方法
            view = super(APIView, cls).as_view(**initkwargs)  # view
            view.cls = cls
            view.initkwargs = initkwargs
            return csrf_exempt(view)
            
        
    class View(object):
        # 2.2、返回View.view方法名
        @classonlymethod
        def as_view(cls, **initkwargs):
    
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)
            return view
    
    
    # 3、url初始化后:
    url(r'^publishers/$',View.view) 
    
    
    # 4、用户开始url,则开始执行View.view()方法,传入原始的request对象,并调用PubliserView的dispatch方法
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs
        return self.dispatch(request, *args, **kwargs)
    
    
    # step 5:PubliserView的父类有dispatch方法
    class PubliserView(APIView):
        pass
    
    class ApiView(View):
        def dispatch(self, request, *args, **kwargs):
            pass
    
    
    # step 6:构建新的request对象
    class ApiView(View):
        def dispatch(self, request, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs
            # 6.1
            request = self.initialize_request(request, *args, **kwargs)
    
    
    # 6.2
    def initialize_request(self, request, *args, **kwargs):
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
        
    
    # 6.3
    class Request(object):
        
        def __init__(...):
            self._request = request
            self._data = Empty
            self._files = Empty
            self._full_data = Empty
            self._content_type = Empty
    
        @property
        def data(self):
            if not _hasattr(self, '_full_data'):
                # 开始封装self._request._post、self._request._file、self._full_data
                self._load_data_and_files()
            return self._full_data
            
        @property
        def query_params(self):
            return self._request.GET
        
        @property
        def POST(self):
            # Ensure that request.POST uses our request parsing.
            if not _hasattr(self, '_data'):
                self._load_data_and_files()
            if is_form_media_type(self.content_type):
                return self._data
            return QueryDict('', encoding=self._request._encoding)
        
        @property
        def FILES(self):
            if not _hasattr(self, '_files'):
                self._load_data_and_files()
            return self._files
    
        
        
        # 6.3.1
        def _load_data_and_files(self):
            if not _hasattr(self, '_data'):
                self._data, self._files = self._parse()
                if self._files:
                    self._full_data = self._data.copy()
                    self._full_data.update(self._files)
                else:
                    self._full_data = self._data
                
                if is_form_media_type(self.content_type):
                    self._request._post = self.POST
                    self._request._files = self.FILES
        
        # 6.3.2
        def is_form_media_type(media_type):
            """
            Return True if the media type is a valid form media type.
            """
            base_media_type, params = parse_header(media_type.encode(HTTP_HEADER_ENCODING))
            return (base_media_type == 'application/x-www-form-urlencoded' or
                    base_media_type == 'multipart/form-data')
  • 相关阅读:
    Windows中的库编程(三、函数调用约定 Calling Convention)
    weui
    js 压缩图片
    django 跨域访问
    html5
    有用的网站
    Chrome
    srpingBoot配置多环境配置文件
    Mysql在查询时不区分大小写
    [CentOS7]Nginx 1.20.1不支持四层负载
  • 原文地址:https://www.cnblogs.com/st-st/p/10122775.html
Copyright © 2011-2022 走看看