drf—— 序列化组件

----->序列化器-Serializer

一、序列化组件介绍

#作用:
    1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
        -Book模型--序列化器--->字典--通过drf:Response--》json格式字符串--->传给前端
    2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
        json格式数据---通过drf:Request-->字典---序列化器---》Book模型
    3. 反序列化,完成数据校验功能

二、序列化组件简单使用

# 序列化的使用
    -写一个序列化类继承serializers.Serializer
    -在类中写要序列化的字段
    -在视图类中,实例化得到一个序列化类的对象,把要序列化的数据传入
        ser=BookSerializer(instance=res,many=True)
    -得到字典
        ser.data就是序列化后的字典

三、序列化组件使用代码实现

'''5个接口
1. 查询所有   Book--》get
2. 查询单个   BookDetali--》get
3. 新增一个   Book--》post
4. 删除一个   BookDetali--》delete
5. 修改一个   BookDetali--》put
'''

1.查询所有

url:127.0.0.1.8000/books/  # 注意最后面的 /一定要写

models.py  # 建立好模型,进行数据迁移,在数据库中手动添加至少2条数据

from django.db import models

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32,null=True) #测试read_only
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.CharField(max_length=32)

urls.py   #配置好路由

path('books/', views.Book.as_view()),

views.py  #写视图类

from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from app01.serializer import BookSerializer

class Book(APIView):
    def get(self, request, *args, **kwargs):
        res = models.Book.objects.all()
        # 借助序列化器
        # 如果是多条,就是many=True
        # 如果是单个对象,就不写
        ser = BookSerializer(instance=res, many=True)
        print(type(ser))  # rest_framework.serializers.ListSerializer
        # 通过序列化器得到的字典
        # ser.data
        print(ser.data)
        return Response(ser.data)

serializer.py  #在app中创建存放序列化器的 类的文件 serializer.py 并写BookSerializer类

# 序列化器类(序列化Book表)
# from rest_framework.serializers import Serializer
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models

class BookSerializer(serializers.Serializer):
    # 要序列化哪个字段
    id = serializers.IntegerField(required=False)
    # id=serializers.CharField()
    title = serializers.CharField(max_length=32,min_length=2,read_only=True)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    # 序列化的时候看不到,因为write_only=True
   publish = serializers.CharField(max_length=32,write_only=True)

2.查询单个

url:127.0.0.1.8000/books/1 #后面的数字代表查询id为几的数据

urls.py中加

re_path('^books/(?P<id>\d+)', views.BookDetail.as_view()),

views.py中加

class BookDetail(APIView):
    def get(self, request, id):
        res = models.Book.objects.all().filter(id=id).first()
        # 单个,去掉many=True
        # 加many=True和不加,ser不是同一个对象,查单个是BookSerializer对象,查多个是ListSerializer对象,这是由源码中元类决定的
        ser = BookSerializer(instance=res)
        print(type(ser))  # 打印出 app01.serializer.BookSerializer
        return Response(ser.data)

3.新增一个  ---这里涉及到保存!!!

ps:新增必须写create方法

urls.py 不变

views.py

class Book(APIView):
    def get(self, request, *args, **kwargs):
        ...

    def post(self, request):
        # post提交的数据都在request.data 是个字典
        print(request.data)
        ser = BookSerializer(data=request.data)
        if ser.is_valid():  # 校验数据是否合法
            ser.save()  # 保存到数据库中
            return Response(ser.data)
        else:
            # 没有校验通过的错误信息
            return Response(ser.errors)
serializer.py
# 如果序列化类继承的是Serializer,必须重写create方法

class BookSerializer(serializers.Serializer):
    ...
    def create(self, validated_data):
        # 为什么要重写create?为了跟views.py里面的Book表建立关系
        res=models.Book.objects.create(**validated_data)
        print(res)
        return res

4.修改

ps:必须写update方法

urls.py不变

views.py

class BookDetail(APIView):
    def get(self, request, id):
        ...

    def put(self, request, id):
        # 通过id取到对象
        res = {'code': 100, 'msg': ''}
        try:
            book = models.Book.objects.get(id=id)
            ser = BookSerializer(instance=book, data=request.data)
            ser.is_valid(raise_exception=True)
            ser.save()
            res['msg'] = '修改成功'
            res['result'] = ser.data

        except Exception as e:
            res['code'] = 101
            res['msg'] = str(e)

        return Response(res)
serializer.py
class BookSerializer(serializers.Serializer):
    ...

    def update(self, book, validated_data):
        book.title=validated_data.get('title')
        book.price=validated_data.get('price')
        book.publish=validated_data.get('publish')
        book.save()
        return book

5.删除

views.py

class BookDetail(APIView):
    ...

    def delete(self,request,id):
        response = {'code': 100, 'msg': '删除成功'}
        models.Book.objects.filter(id=id).delete()
        return Response(response)

四、序列化类字段类型和字段参数

# 常用字段类型
    -IntegerField
    -CharField
    -DecimalField
    -DateTimeField
    -。。。跟models中大差不差

# 常用字段参数
    -选项参数
        max_length    最大长度
        min_lenght    最小长度
        allow_blank    是否允许为空
        trim_whitespace    是否截断空白字符
        max_value    最小值
        min_value    最大值

    -通用参数
        #重点
        read_only    表明该字段仅用于序列化输出,默认False
        write_only    表明该字段仅用于反序列化输入,默认False

        # 掌握
        required    表明该字段在反序列化时必须输入,默认True
        default        反序列化时使用的默认值
        allow_null    表明该字段是否允许传入None,默认False

        # 了解
        validators    该字段使用的验证器
        error_messages    包含错误编号与错误信息的字典

---------------------序列化器-------------------------

五、序列化器的(反序列化之)保存功能

同三中3.增加一个 里面的保存

六、序列化器的(反序列化之)字段校验功能

validators校验,局部钩子,全局钩子

ps:validators 列表里面可以传多个值进行校验

# 三种方式
    -字段自己的校验规则(max_length...)
    -validators的校验
        publish = serializers.CharField(max_length=32,validators=[check,])

        def check(data):
        if len(data)>10:
            raise ValidationError('最长不能超过10')
        else:
            return data
    -局部和全局钩子
        # 局部钩子,validate_字段名,需要带一个data,data就是该字段的数据
    def validate_title(self, data):
        if data.startswith('sb'):
            raise ValidationError('不能以sb开头')
        else:
            return data
    # 全局钩子
    def validate(self, attrs):
        title=attrs.get('title')
        publish=attrs.get('publish')
        if title==publish:
            raise ValidationError('书名不能跟出版社同名')
        else:
            return attrs

七、序列化类常用字段参数之read_only和write_only

read_only    表明该字段仅用于序列化输出,默认False
    write_only    表明该字段仅用于反序列化输入,默认False

    class BookSerializer(serializers.Serializer):
        # 要序列化哪个字段
        id = serializers.IntegerField(required=False)
        # id=serializers.CharField()
        title = serializers.CharField(max_length=32,min_length=2,read_only=True)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        # 序列化的时候看不到
        publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)

八、(反序列化之)高级用法之source

总结:

1用法一: 修改返回到前端的字段名
    # 若source=title 那么字段名就不能再叫title,这里叫了name
    name = serializers.CharField(max_length=32,min_length=2,source='title')
2用法二: 如果表模型中有方法
class Book(models.Model):
    ...
    def test(self):
        # python是强类型语言,不支持字符串和数字直接相加
        return self.title+str(self.price)
    # 执行表模型中的test方法,并且把返回值赋值给xxx
    xxx=serializers.CharField(source='test')
3用法三: source支持跨表操作
    addr=serializers.CharField(source='publish.addr')

# 可以去看源码,内部如何实现的

代码:

urls.py

models.py

from django.db import models

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32,null=True) #测试read_only
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # publish = models.CharField(max_length=32)
    #修改后
    publish = models.ForeignKey(to='Publish',null=True,on_delete=models.CASCADE)
    #这是在测试source第一种方法时加的
    def test(self):
        # python是强类型语言,不支持字符串和数字直接相加
        return self.title+str(self.price)

#新建一张publish表
class Publish(models.Model):
    name=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)
    #重写__str__
    def __str__(self):
        return self.name

views.py

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
#方法一
    name = serializers.CharField(max_length=32,min_length=2,source='title')
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
#方法三,要直接显示出publish的名字 ,或 在models.py中重写__str__
publish = serializers.CharField(max_length=32,source='publish.name')
#方法二
    xxx=serializers.CharField(source='test')
#方法三:跨表
    publish_addr=serializers.CharField(source='publish.addr')

九、模型类序列化器

1 原来用的Serilizer跟表模型没有直接联系, 模型类序列化器ModelSerilizer,跟表模型有对应关系

2 使用
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model=表模型    # 跟哪个表模型建立关系
            fields=[字段,字段] # 序列化的字段,反序列化的字段
            fields='__all__' # 所有字段都序列化,反序列化
            exclude=[字段,字段] # 排除哪些字段(不能跟fields同时使用)
            read_only_fields=['price','publish']  # 序列化显示的字段
            write_only_fields=['title']           # 反序列化需要传入的字段
            extra_kwargs ={'title':{'max_length':32,'write_only':True}}
            depth=1  # 了解,跨表1查询,最多建议写3
        # 重写某些字段
        publish = serializers.CharField(max_length=32,source='publish.name')
        # 局部钩子,全局钩子,跟原来完全一样
3 新增,修改
    -统统不用重写create和update方法了,在ModelSerializer中重写了create和update

十、(反序列化之)高级用法之SerializerMethodField

#方式一:Serializer
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    name = serializers.CharField(max_length=32,min_length=2,source='title')
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publish = serializers.SerializerMethodField()
    def get_publish(self,obj):
        dic={'name':obj.publish.name,'addr':obj.publish.addr}
        return dic

#方式二:ModelSerializer
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'
    publish = serializers.SerializerMethodField()
    def get_publish(self,obj):
        dic={'name':obj.publish.name,'addr':obj.publish.addr}
        return dic

# 方式三:使用序列化类的嵌套
class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        # fields = '__all__'
        fields = ['name','addr']

class BookModelSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()

    class Meta:
        model = models.Book
        fields = '__all__'

十一、序列化组件源码分析

#序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
#序列化对象.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)

相关推荐

  • python测试开发django-rest-framework-88.反序列化

    前言 serializers.Serializer可以对modle模型中的字段序列化,并且必须写create和update两个方法.ModelSerializer可以看成是Serializer的一个升 ...

  • python测试开发django-31.admin后台一对多关系

    前言 平常的网页上有很多一对多的场景,比如填写银行卡信息的时候,会从银行列表下拉框选择对应的银行信息.一般会建两张表,一张表放银行的信息,一张表放银行卡信息. 每个银行可以对应多个银行卡,每个银行卡只 ...

  • 11 Serializer组件

    知识点:Serializer(偏底层).ModelSerializer(重点).ListModelSerializer(辅助群改) 为什么要使用序列化组件? 视图中查询到的对象和queryset类型不 ...

  • python测试开发django-64.序列化(Serializer)

    前言 REST framework中的serializers与Django的Form和ModelForm类非常像.我们提供了一个Serializer类,它为你提供了强大的通用方法来控制响应的输出, 以 ...

  • python测试开发django-20.添加创建时间DateTimeField

    前言 我们在admin后台发布一篇文章的时候,一般会有创建时间和最后更新时间这2个字段,创建时间就是第一次编辑文章的时候自动添加的,最后更新时间就是每次修改文章的内容后自动更新 在models.py建 ...

  • python测试开发django-12.主键primary_key

    前言 django的models新增数据库表时,如果不设置主键,会默认新增一个id为主键,如果我们想自己设置一个字段为主键,需加个参数primary_key=True 默认id主键 新增一张用户表,表 ...

  • python测试开发django-39.页面布局form_layout

    前言 xadmin的详情页面默认是一行展示一个字段,可以使用form_layout对详情页面的布局重新设计. 可以设置必填和非必填字段,也可以设置不显示,不可以编辑的字段. models模块 先在mo ...

  • python测试开发django-65.序列化(ModelSerializer)

    前言 serializers.Serializer可以对modle模型中的字段序列化,并且必须写create和update两个方法.ModelSerializer可以看成是Serializer的一个升 ...

  • DjangoRestFramework使用

    目录: 1.1 DjangoRestFramework基本使用 1.2 drf认证&权限 模块 1.3 djangorestframework 序列化 1.4 djangorestframew ...

  • drf—— 编写登录接口,用同一个接口既可以不登录访问,又可以登录访问

    要求: 编写登录接口,一个接口既可以不登录访问,又可以登录访问(匿名用户一分钟访问1次,登录用户一分钟访问3次) #需要用到student和user表 1.models.py from django. ...