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

 

posted @ 2018-12-15 11:08  st--st  阅读(189)  评论(0编辑  收藏  举报