rest-framework之序列化组件

 drf框架用于前后端分离开发,分离开发的数据交互是通过json格式的数据来完成的。我们之前通过将字典序列化返回出去,其实drf框架本身就自带了序列化的组件。

一、django自带序列化组件

django也有自带的序列化组件,但是它默认是携带很多不需要的数据,不能控制其携带的数据,因此只做了解即可。

from django.core import serializers
def test(request):
    book_list = models.Book.objects.all()    
    ret = serializers.serialize("json", book_list)
    return HttpResponse(ret)

返回的结果(其中二进制的数据是汉字转码)

[{"model": "app01.book", "pk": 1, "fields": {"name": "\u5251\u6765", "publish": "\u5317\u4eac\u51fa\u7248\u793e"}}, {"model": "app01.book", "pk": 2, "fields": {"name": "\u96ea\u4e2d\u608d\u5200\u884c", "publish": "\u4e0a\u6d77\u51fa\u7248\u793e"}}]

二、 序列化组件

使用drf的序列化组件:

  • 首先要新建一个序列化类继承Serializer
  • 在类中写要序列化的字段

在视图中使用序列化的类:

  •  实例化序列化的类产生对象,在产生对象的时候,传入需要序列化的对象(queryset)
  • return Response(对象.data)

 高级用法:

  • source:可以指定字段(name   publish.name),可以指定方法,
  • SerializerMethodField搭配方法使用(get_字段名字)  
publish_detail = serializers.SerializerMethodField(read_only=True)
def get_publish_detail(self, obj):
    return {'name':obj.publish.name,'city':obj.publish.city}
  • read_only:反序列化时,不传
  • write_only:序列化时,不显示

三、序列化的两种方式

models.py

from django.db import models


class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField(null=True)
    types = models.IntegerField(choices=((0, '文学类'), (1, '情感类')), default=1, null=True)
    publish = models.ForeignKey(to='Publish', to_field='id', on_delete=models.CASCADE, null=True)
    authors = models.ManyToManyField(to='Author')
    def __str__(self):
        return self.name

    def test(self):
        return 'xxx'


class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()


class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()
    def __str__(self):
        return self.name

3.1、Serializers:没有指定表模型

创建完表之后,首先要对其中的字段进行序列化,我们新建了一个类去继承serializers.Serializer的类。

反序列化通过create方法完成

from app01 import models
from rest_framework import serializers


class AuthorSerializer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.CharField()


class BookSerializer(serializers.Serializer):
    """为了不把表内的名字暴露,可以返回别名,然后用source指定模型表中的字段名,但是别名不能与表中的字段名重名"""
    names = serializers.CharField(source='name')
    '''
    write_only:序列化的时候,该字段不显示
    read_only:反序列化的时候,该字段不传
    '''
    price = serializers.CharField(write_only=True)
    '''出版社的详情在另一张表,如果要取出版社的city,需要使用source="publish.city" '''
    publish = serializers.CharField(source='publish.name',read_only=True)
    '''source不但可以指定一个字段,还可以指定一个方法'''
    book_type = serializers.CharField(source='get_types_display', read_only=True)
    '''序列化出版社的详情:指定SerializerMethodField之后,可以对应一个方法,
    返回什么内容,publish_detail就是什么内容'''
    publish_detail = serializers.SerializerMethodField(read_only=True)
    # 对应的方法名字格式固定:get_字段名
    def get_publish_detail(self, obj):
        print(type(obj))  # <class 'app01.models.Book'>
        return {'name': obj.publish.name, 'city': obj.publish.city}
    # 返回所有作者信息
    authors = serializers.SerializerMethodField(read_only=True)
    def get_authors(self, obj):  # obj就是要序列化的对象
        '''可以直接返回一个列表推导式:
        return [ {'name':author.name,'age':author.age} for author in obj.authors.all()]
        也可以写一个Author的序列化类,调用它来进行序列化
        '''
        authorser = AuthorSerializer(obj.authors.all(), many=True)
        return authorser.data
    # 反序列化的校验:局部校验:validate_字段名(如果起别名就是别名)
    def validate_names(self, value):  # value就是前端传过来的值
        if value.startswith('sb'):
            raise ValidationError('不能以sb开头')
        return value

    # 反序列化,重写了create方法
    def create(self, validated_data):
        res = models.Book.objects.create(**validated_data)
        return res

 然后我们要在视图函数中写CBV,把我们查处来的Book的queryset对象传到序列化的类里面进行序列化,序列化完毕后,可以通过序列化的类实例化得到的对象.data的方法拿到结果,然后用Response返回json格式的数据,Response实际上也是继承了HttpResponse。

from rest_framework.views import APIView
from app01 import models
from rest_framework.response import Response
# 把对象转换成json格式字符串
from app01.app01_serializer import BookSerializer
class Books(APIView):
    def get(self, request):
        response = {'code': 100, 'msg': '查询成功'}
        books = models.Book.objects.all()
        '''
       如果序列化多条,即queryset对象,就要写many=True;
       如果只序列化一条,就可以不写;
       instance是要序列化的对象 
       '''
        bookser = BookSerializer(instance=books, many=True)
        # print('view:',type(bookser.data))
        # view: <class 'rest_framework.utils.serializer_helpers.ReturnList'>
        response['data'] = bookser.data
        return Response(response)

    # 使用继承了Serializers序列化类的对象,反序列化
    def post(self, request):
        # 实例化产生一个序列化的对象,data是要反序列化的字典
        bookser = BookSerializer(data=request.data)
        if bookser.is_valid():
            # 清洗通过的数据
            res = bookser.create(bookser.validated_data)
        print(bookser.errors)
        return Response()

 然后通过postman向后台发GET请求,可以拿到返回的数据:http://127.0.0.1:8000/books

{
    "code": 100,
    "msg": "查询成功",
    "data": [
        {
            "names": "剑来",
            "publish": "北京出版社",
            "book_type": "情感类",
            "publish_detail": {
                "name": "北京出版社",
                "city": "北京"
            },
            "authors": [
                {
                    "name": "烽火戏诸侯",
                    "age": "30"
                }
            ]
        },
        {
            "names": "诛仙",
            "publish": "上海出版社",
            "book_type": "文学类",
            "publish_detail": {
                "name": "上海出版社",
                "city": "上海"
            },
            "authors": [
                {
                    "name": "萧鼎",
                    "age": "40"
                }
            ]
        }
    ]
}

 然后再来看反序列化,我们之前已经写了create方法来完成反序列化的工作,下面先来写一下视图函数的post方法,利用post方法来完成反序列化的工作。post的视图函数已经在上面写了。我们通过postman给后端发一个post请求。

 

数据库中数据成功插入:

 

3.2、 ModelSerializers:指定了表模型

  • ModelSerializers:指定了表模型

    class Meta:
        model=表模型
        
# 要显示的字段
        fields=('__all__')
        fields=('id','name')
        
# 要排除的字段
        exclude=('name')
      
 # 深度控制
        depth=1

  • 重写某个字段

        在Meta外部,重写某些字段,方式同Serializers

 序列化的文件:app01_serializer.py

from app01 import models
from rest_framework import serializers
from rest_framework.exceptions import ValidationError


class AuthorSerializer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.CharField()


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        # 指定要序列化的表模型
        model = models.Book
        # 指定要序列化的字段,'__all__'就是所有字段
        # exclude = ('name',),表示除了name字段都序列化
        # fields = ('id', 'name')
        fields = '__all__'
        # 跨表深度,最好不要超过3
        depth = 1
    # 可以在Meta外面对外键字段重写,拿到详细信息
    authors = serializers.SerializerMethodField()
    def get_authors(self, obj):
        res = AuthorSerializer(instance=obj.authors.all(), many=True)
        return res.data
    # 反序列化的全局校验validate
    def validate(self, attrs):
        if attrs.get('price') <= 0:
            raise ValidationError('价格不能为负数')
        return attrs

视图函数:

from rest_framework.views import APIView
from app01 import models
from rest_framework.response import Response
# 把对象转换成json格式字符串
from app01.app01_serializer import BookSerializer
class Books(APIView):
    def get(self, request):
        response = {'code': 100, 'msg': '查询成功'}
        books = models.Book.objects.all()
        '''
       如果序列化多条,即queryset对象,就要写many=True;
       如果只序列化一条,就可以不写;
       instance是要序列化的对象 
       '''
        bookser = BookSerializer(instance=books, many=True)
        # print('view:',type(bookser.data))
        # view: <class 'rest_framework.utils.serializer_helpers.ReturnList'>
        response['data'] = bookser.data
        return Response(response)

    # 使用继承了ModelSerializers序列化类的对象,反序列化
    def post(self, request, *args, **kwargs):
        # 实例化产生一个序列化类的对象,data是要反序列化的字典
        bookser = BookSerializer(data=request.data)
        if bookser.is_valid():
            bookser.save()
        else:
            print(bookser.errors)
        return Response()

3.3、反序列化

"""
-反序列化的校验
	-validate_字段名(self,value):
		-如果校验失败,抛出ValidationError(抛出的异常信息需要去bookser.errors中取)
		-如果校验通过直接return value
	-validate(self,attrs)
		-attrs所有校验通过的数据,是个字典
		-如果校验失败,抛出ValidationError
		-如果校验通过直接return attrs
"""

反序列化已经在序列化的示例中加入了,通过post方法完成反序列化,继承serializers.Serializer的类需要在序列化的类中重写create方法。

继承serializers.ModelSerializer类的不用重写,在校验通过后,直接调用save方法即可。

四、源码分析

1、序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象

 

2、序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找);Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance);再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source;然后执行get_attribute方法,source_attrs。当参数传过去,判断是方法就加括号执行,是属性就把值取出来

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值