zoukankan      html  css  js  c++  java
  • 🍖drf 序列化组件

    一.序列化器介绍 (Serializer)

    1.Python中的序列化与反序列化

    • 序列化 : 将Python中的对象转成就送格式的字符串
    • 反序列化 : 将python格式的字符串转成Python中的对象

    2.序列化器的作用

    • 序列化, 序列化器会把模型对象转换成字典, 经过 response 以后变成json字符串
    1. 反序列化, 把客户端发送过来的数据,经过 request 以后变成字典, 序列化器可以把字典转成模型
    2. 反序列化, 完成数据校验功能

    3.注意

    • drf 中的序列化组件是先把对象转成字典格式, 因为字典格式可以直接放进 Response 中

    二.序列化器的简单使用

    1.使用步骤

    • 写一个序列化的类,并继承Serializer

    • 在类中写要序列化的字段, 序列化字段类(有很多, 常用的就几个, 等同于models中的字段类)

    • 在视图类中使用, 导入序列化类把要序列化的对象传入, 得到序列化对象

    • 可以通过[序列化类的对象].data获取序列化后的字典

    ps : 如果不使用rest_framework提供的Response,就得使用JsonResponse

    2.代码示例

    • models.py 创建模型类
    from django.db import models
    class Book2(models.Model):
        nid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)
        price = models.IntegerField(max_length=8)
        author = models.CharField(max_length=16)
        publish = models.CharField(max_length=16)
    
    • serializers.py 创建序列化器
    from rest_framework import serializers
    from rest_framework.serializers import ModelSerializer
    from drf_test import models
    
    # 定义一个序列化器,继承ModelSerializer
    class BookSerializer2(serializers.Serializer):
        # 里面书写想要序列化的字段,想序列哪个就书写哪个
        title = serializers.CharField()
        price = serializers.IntegerField()
    
    • views.py 书写视图类
    from rest_framework.viewsets import ModelViewSet
    from drf_test.serializers import BookSerializer2
    from drf_test import models
    
    class Book2View(APIView):
        def get(self,request,id):
            # 从数据库中获取到Book的对象
            book_obj = models.Book2.objects.filter(nid=id).first()
            # 将book_obj放进我们写的序列化器里面进行序列化
            book_ser = BookSerializer2(book_obj)
            # [序列化对象].data就是序列化后得到的字典
            return Response(book_ser.data)
    
    • urls.py 文件
    re_path('^books/(?P<id>d+)', views.Book2View.as_view()),
    
    • 开启项目测试

    image-20210412225227378

    image-20210412225457174

    三.序列化类的字段类型与参数

    1.常用字段类型

    字段 字段构造方式
    BooleanField BooleanField()
    NullBooleanField NullBooleanField()
    CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
    EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
    RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
    SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
    URLField URLField(max_length=200, min_length=None, allow_blank=False)
    UUIDField UUIDField(format='hex_verbose') format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
    IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
    IntegerField IntegerField(max_value=None, min_value=None)
    FloatField FloatField(max_value=None, min_value=None)
    DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
    DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
    DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
    TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
    DurationField DurationField()
    ChoiceField ChoiceField(choices) choices与Django的用法相同
    MultipleChoiceField MultipleChoiceField(choices)
    FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ListField ListField(child=, min_length=None, max_length=None)
    DictField DictField(child=)

    2.字段参数

    • 针对 CharField 类型
    参数 作用
    max_length 最大长度
    min_lenght 最小长度
    allow_blank 是否允许为空
    • 针对 InterField 类型
    参数 作用
    max_value 最小值
    min_value 最大值
    • 通用参数 (所有字段都有的)
    参数 作用
    read_only 表明该字段仅用于序列化输出,默认False
    write_only 表明该字段仅用于反序列化输入,默认False
    required 表明该字段在反序列化时必须输入,默认True
    default 反序列化时使用的默认值
    allow_null 表明该字段是否允许传入None,默认False
    validators 该字段使用的验证器
    error_messages 包含错误编号与错误信息的字典
    label 用于HTML展示API页面时,显示的字段名称
    help_text 用于HTML展示API页面时,显示的字段帮助提示信息

    四.序列化器的数据校验及数据保存

    1.数据的校验

    • 与前面学的 forms 组件的数据校验方式类似, 都是调用 is_valid() 方法进行校验

    • 先对字段自带校验规则进行校验, 然后局部钩子, 最后全局钩子(第五小节介绍)

    • 使用序列化器进行反序列化时, 需要对数据进行验证后, 才能获取验证成功的数据或保存成模型类对象

    # 在视图类中书写
    class PublishView(APIView):
        # 新增数据方法
        def post(self,request):
            # 传入前端提交的json格式数据,拿到反序列化的对象
            publish_ser = serializer.PublishSerializer(data=request.data)
            # 使用 is_valid() 方法进行数据校验,返回 True 和 False
            if publish_ser.is_valid():
                # 手动保存
                # 拿到创建的对象
                res = modeels.Publish.objects.create(**publish_ser.validated_data)
                # 将其赋值给instance
                publish_ser.instance = res
                return Response(publish_ser.data)
            else:
                return Response(publish_ser.errors)
    

    2.数据的保存

    • 上面我们通过手动将新增对象赋值给序列器对象的instance来进行保存
    • 其实我们可以直接使用序列器对象的.save()方法来实现保存
    • 但是使用.save()方法人家就规定你必须重写该方法 :

    如果继承了Serializer, 但凡是数据的新增还是更新, 调用 .save() 方法进行数据保存的时候都需要重写 create方法和 update方法, 如果继承的是ModelsSerializer则不需要重写

    • serializer.py 序列化器内重写方法
    from rest_framework import serializers
    
    class PublishSerializer(serializers.Serializer):
        ...
        
        # 重写create方法
        def create(self,valodated_data):
            res = models.Punlish.objects.create(**validated_data)
            return res
            
        # 重写update方法
        def update(self,instance,validated_data):
            # 手动获取数据进行赋值修改
            name = validated_data.get('name')
            city = validated_date.get('city')
            email = validated_data.get('email')
            instance.name = name
            instance.city = city
            instance.email = email
            instance.save()
            return instance
    
    • views.py 视图类中使用 .save()
    class PublishView(APIView):
        ...
        
        # 新增数据
        def post(self,request):
            publish_ser = serializer.PublishSerializer(data=request.data)
            if publish_ser.is_valid():
                # 直接调用 .save() 保存
                publish_ser.save()
                return Response(publish_ser.data)
            else:
                return Response(publish_ser.errors)
            
    class PublishDetailView(APIView):
        ...
        
        # 修改数据
        def put(self,request,id):
            publish = models.Publish.objects.filter(pk=id).first()
            # 传入前端要修改的对象及传过来的数据 
            publish_ser = serializer.PublishSerializer(instance=publish,data=request.data)
            # 得到反序列化的对象进行校验
            if publish_ser.is_valid():
                publish_ser.save()
                return Response(publish_ser.data)
            else:
                return Response(publish_ser.errors)
    

    输出的错误信息(errors)是英文, 要想让错误显示的是中文自定义的话, 方法与 forms 组件的方法是一样的 : 再模型类字段中添加 error_massages 参数来指定

    3.数据保存之重写save方法

    • 还有一种就是重写 save 方法, 但官方不推荐重写该方法 (作为了解)

    • 序列化类中重写save

    class PublishSerializer(serializers.Serializer):
        ...
    	
    	# 重写save
        def save(self, **kwargs):  # kwargs是校验过后的数据
            # 在父类的save内部, 调用了create, 所以我们重写create,将数据传入
            res=models.Publish.objects.create(**kwargs)
            return res
    
    • 视图类中的使用
    class PublishView(APIView):
        ...
        
        # 新增数据
        def post(self,request):
            publish_ser = serializer.PublishSerializer(data=request.data)
            if publish_ser.is_valid():
                # 重写save需要手动传参
                res = publish_ser.save(**publish_ser.validated_data)
                publish_ser.instance = res
                return Response(publish_ser.data)
            else:
                return Response(publish_ser.errors)
    

    4.is_valid( ) 的 raise_exception 参数

    • is_valid() 方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception = True参数开启,REST框架接收到此异常,会向前端返回HTTP 400错误的请求响应
    publish_ser.is_valid(raise_exception=True)
    

    五.序列化器三种字段校验方法

    1.序列化器内字段自带的校验

    # 在书写序列化类字段时加入参数来控制校验条件
    class PublishSerializer(serializers.Serializer):
        nid = serializers.IntegerField(required=False)  # 必填
        name = serializers.CharField(min_length=3)     # 最短长度为3
        city = serializers.CharField(max_length=16)    # 最长为16
        email = serializers.EmailField()
    

    2.使用钩子函数(全局钩子, 局部钩子)

    • 局部钩子 : validate_[字段名]
    # 校验名字不能以"xxx"开头
    def validate_name(self, data):
        # data就是当前字段的值
        if data.startswith('xxx'):
       	    raise ValidationError('不能以"xxx"开头')
        else:
            return data  # 返回校验后的值
    
    • 全局钩子 : validate
    # 校验名字不能与所在城市同名
    def validate(self, attrs): 
        name = attrs.get('name')
        city = attrs.get('city')
        if name == city:
            raise ValidationError('名字不能和城市名一样!')
        else:
            return attrs  # 返回所有数据
    

    3.使用字段参数 validators 来进行校验

    • 该参数可以指定校验函数, 适用于多个字段都要进行同一种校验
    • 如果每个都写钩子就很麻烦, 于是就可以写一个校验函数, 每个字段都使用 validators 参数来指定该函数
    # 定义一个校验函数
    def name_start(data):
        if data.startswith('xxx'):
            raise ValidationError('不能以"xxx"开头')
        else:
            return data
            
    # 然后在需要进行该校验的字段中加入 validators 参数指定该校验函数
    author = serializers.CharField(validators=[name_start])
    ...
    city = serializers.CharField(validators=[name_start])
    ...
    

    六.read_only 和 write_only

    1.常用字段参数

    • read_only:表明该字段仅用于序列化输出,默认False(只能查看,不能修改)
    • write_only:表明该字段仅用于反序列化输入,默认False(只能修改,不能查看)

    2.代码示例

    • urls.py
    re_path('^books/(?P<id>d+)', views.Book2View.as_view()),
    
    • models.py
    class Book2(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=16)
        price = models.IntegerField()
        author = models.CharField(max_length=16, null=True)
        publish = models.CharField(max_length=16, null=True)
    
    • serializers.py
    from rest_framework import serializers
    
    
    class BookSerializer2(serializers.Serializer):
        name = serializers.CharField(max_length=16)
        price = serializers.IntegerField()
        # read_only=True:该字段只用于序列化输出,只能看不能修改
        author = serializers.CharField(max_length=16, read_only=True)
        # write_only=True:该字段只用于反序列化输入,只能改不能查看
        publish = serializers.CharField(max_length=19, write_only=True)
    
        def update(self, instance, validated_data):
            instance.title = validated_data.get('name')
            instance.price = validated_data.get('price')
            instance.author = validated_data.get('author')
            instance.publish = validated_data.get('publish')
            instance.save()
            return instance
    
    • views.py
    from mydrf.serializers import BookSerializer2
    from mydrf import models
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    
    class Book2View(APIView):
        def get(self, request, id):
            book_obj = models.Book2.objects.filter(nid=id).first()
            book_ser = BookSerializer2(book_obj)
            return Response(book_ser.data)
    
        def put(self, request, id):
            book_obj = models.Book2.objects.filter(nid=id).first()
            book_ser = BookSerializer2(instance=book_obj, data=request.data)
            if book_ser.is_valid():
                book_ser.save()
                return Response(book_ser.data)
            else:
                return Response(book_ser.errors)
    
    • 查询

    image-20210413191500453

    • 修改

    image-20210413191655817

    image-20210413191728499

    image-20210413191822931

    image-20210413191848963

    七.实现增删改查接口

    1.需求

    • 数据库表 : Book, Author, AuthorDatail, Publish, 表之间建好关联
    • 实现查全部, 查某条, 新增, 修改, 删除接口
    • 出版社名字不能有"xxx"敏感字

    2.代码实现

    • models.py
    from django.db import models
    
    
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField()
    
        publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
        authors = models.ManyToManyField(to='Author')
    
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_datail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE)
    
    
    class AuthorDatail(models.Model):
        nid = models.AutoField(primary_key=True)
        telephone = models.BigIntegerField()
        birthday = models.DateField()
        addr = models.CharField(max_length=64)
    
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32, null=True)
        email = models.EmailField()
    
        def __str__(self):
            return self.name
    
    • serializers.py
    from mydrf import models
    from rest_framework import serializers
    from rest_framework.exceptions import ValidationError
    
    
    class PublishSerializer(serializers.Serializer):
        nid = serializers.IntegerField(required=False)
        name = serializers.CharField(max_length=16)
        city = serializers.CharField(max_length=32,error_messages={"max_length": "太长"})
        email = serializers.EmailField()
    
        # 重写create
        def create(self, validated_data):
            res = models.Publish.objects.create(**validated_data)
            return res
    
        # 重写update
        def update(self, instance, validated_data):
            instance.name = validated_data.get('name')
            instance.city = validated_data.get('city')
            instance.email = validated_data.get('email')
            instance.save()
            return instance
    
        # 局部钩子,校验出版社名字
        def validate_name(self, data):
            if "小黄书" in data:
                raise ValidationError(f'存在敏感字符{data}')
            else:
                return data
    
        # 全局钩子
        def validate(self, attrs):
            name = attrs.get('name')
            city = attrs.get('city')
            if name == '小黑出版社' and city == "上海":
                raise ValidationError('该出版社已被列入黑名单')
            return attrs
    
    • views.py
    from mydrf.serializers import PublishSerializer
    from mydrf import models
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    
    class PublishView(APIView):
        # 获取所有书
        def get(self, request):
            publish_qs = models.Publish.objects.all()
            publish_ser = PublishSerializer(instance=publish_qs, many=True)  # 有多条数据的时候一定要添加
            return Response(publish_ser.data)
    
        # 新增数据
        def post(self, request):
            publish_ser = PublishSerializer(data=request.data)
            if publish_ser.is_valid():
                publish_ser.save()
                return Response(publish_ser.data)
            else:
                # publish_ser.errors
                return Response("error")
    
    
    class PublishView2(APIView):
        # 获取一条
        def get(self, request, id):
            publish_obj = models.Publish.objects.filter(pk=id).first()
            publish_ser = PublishSerializer(instance=publish_obj)
            return Response(publish_ser.data)
    
        # 修改数据
        def put(self, request, id):
            publish_obj = models.Publish.objects.filter(pk=id).first()
            publish_ser = PublishSerializer(instance=publish_obj, data=request.data)
            if publish_ser.is_valid():
                publish_ser.save()
                return Response(publish_ser.data)
            else:
                return Response(publish_ser.errors)
    
        # 删除数据
        def delete(self, request, id):
            # 直接删除数据,拿到影响条数的一个列表
            rows = models.Publish.objects.filter(pk=id).delete()
            # 取出来判断一下
            if rows[0] > 0:
                return Response('数据删除成功!')
            else:
                return Response('数据不存在!')
    
    • urls.py
    path('publish/', views.PublishView.as_view()),
    path('publish/<int:id>', views.PublishView2.as_view()),
    

    3.测试效果

    • 查所有出版社

    image-20210413221436453

    • 新增出版社

    image-20210413221602736

    image-20210413221615576

    • 带敏感字创建不了

    image-20210413211209780

    image-20210413211220085

    • 黑名单创建不了

    image-20210413211313956

    image-20210413211337002

    • 查某一条

    image-20210413221751039

    • 修改数据

    image-20210413222032741

    image-20210413222040763

    • 删除数据

    image-20210413221915254

    image-20210413221928971

    • 删除不存在的数据

    image-20210413212235142

    八.source 参数

    用来指定要序列化的字段(数据表中的字段), 一般使用在一个字段情况, 可以跨表, 可以执行方法并执行

    • 不指定,默认就是字段名,必须跟数据库对应
    • 指定了source就可以给字段改名了
    # 更改字段名
    "[另取的名字]" = serializers.CharField(source='publish')  # 指定需要序列化的字段是publish
    
    # 跨表
    publish = serializers.CharField(source='publish.city')
    
    # 执行方法,指定一个定义在模型类内方法的内存地址,会自动加括号执行
    pub_date = serializers.CharField(source='times')
    

    九.SerializerMethodField( )

    一般用于跨表查询, 在序列化器内部写一个get_[外键名],会显示指定的数据(就是显示多张表的结果)

    1.需求

    • 获取书籍信息, 并获取到该数据下的出版社信息以及所有的作者信息

    2.方式一 : 使用 SerializerMethodField 实现

    • serializers.py
    class BookSerializer(serializers.Serializer):
        name = serializers.CharField()
        price = serializers.IntegerField()
    
        # 取出该书的出版社
        publish = serializers.SerializerMethodField()
        def get_publish(self, obj):
            return {'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email}
    
        # 取出该书的所有作者
        authors = serializers.SerializerMethodField()
        ## for循环出所有作者
        # def get_authors(self, obj):
        #     li = []
        #     for author in obj.authors.all():
        #         li.append({'id':author.nid,'name':author.name,'age':author.age})
        #         return li
    
        # 列表生成式书写
        def get_authors(self, obj):
            return [{'id': author.nid, 'name': author.name, 'age': author.age} for author in obj.authors.all()]
    
    • views.py
    from mydrf.serializers import BookSerializer
    
    class BookView(APIView):
        def get(self, request):
            book_qs = models.Book.objects.all()
            book_ser = BookSerializer(instance=book_qs, many=True)
            return Response(book_ser.data)
    
    • urls.py
    path('books/', views.BookView.as_view()),
    
    • 测试效果

    image-20210413231413002

    3.方式二 : 在模型类中书写方法

    该方法可以自定义输出的内容, 比如对一些数据进行处理后返回前端(身份证中间部分加"*****")

    • models.py
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField()
    
        publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
        authors = models.ManyToManyField(to='Author')
    
        def __str__(self):
            return self.name
    
        # 取出该书的出版社
        def get_publish(self):
            return {'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email}
    
        # 取出该数的所有作者
        def get_author(self):
            return [{'id': author.nid, 'name': author.name, 'age': author.age} for author in self.authors.all()]
    
    • serializers.py
    class BookSerializer(serializers.Serializer):
        name = serializers.CharField()
        price = serializers.IntegerField()
    
        # 获取出版社和作者
        publish = serializers.DictField(source="get_publish")
        authors = serializers.ListField(source="get_author")
    
    • 测试效果

    image-20210414000657149

    十.模型类序列化器

    1.Serializer 与 ModelSerializer

    • 上面我们使用的 Serializer 序列化类它不是只能为数据库模型类定义, 也可以为非数据库模型类的数据定义 (也就是自己定义的数据进行序列化 : {"name":"shawn","age":18}),
    • serializer是独立于数据库之外的存在, 需要自己在序列化类中去指定模型类的字段
    • 而如果我们想要使用序列化器对应的是Django的模型类, DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类

    2.ModelSerializer 相比较于 Serializer 提供了一些功能

    • 基于模型类自动生成一系列字段 (也就是不再需要自己手动定义字段)
    • 基于模型类自动为 Serializer 生成 validators,比如 : unique_together
    • 包含默认的create( )update( )的实现, 不再需要重写这两种方法

    3.模型类序列化器的定义

    • model : 指明参照哪个模型类
    • fields : 指明为模型类的哪些字段生成
    class AuthorDatailSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.AuthorDatail
            fields = '__all__'
    
    • exclude : 可以排除某这些字段, 不能与 fields 同时存在
    class AuthorDatailSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.AuthorDatail
            exclude = ('phone',)
    
    • depth : 显示的深度一本书有作者, 作者有作者信息, 定义该参数会一层层显示, 层数自己控制(了解)
    • read_only_field : 指明只读字段, 仅用于序列化输出的字段 (弃用,有更好的方法)
    • wirte_only_field : 指明只写字段, 仅用于反序列化输入的字段 (弃用)
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            exclude = ('age',)
            depth = 3
            read_only_fields = ('nid', 'price')
            ...
    
    • extra_kwargs : 使用该参数为ModelSerializer添加或修改原有的选项参数 (重点, 更好的方法)
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
            extra_kwargs = {
                'price': {'min_value': 0, 'required': True},
                'publish': {'required': True, 'read_only_fields' : True},
            }
    

    4.练习 : 使用一个接口来同时新增 Author 和 AuthorDetail 表

    模型表还是上面创建的模型表, 只是新增了点东西

    • models.py
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_datail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE)
    		
        # 获取用户的详情    
        def get_detail(self):
            return {"telephone":self.author_datail.telephone,"addr":self.author_datail.addr,"birthday":self.author_datail.birthday}
    
    • serializers.py
    class AuthorSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Author
            fields = ['nid', 'name', 'age', 'detail', 'author_datail']
    
        # 获取用户信息数据
        detail = serializers.DictField(source="get_detail", read_only=True)
    
    
    class AuthorDatailSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.AuthorDatail
            fields = '__all__'
    
    • views.py
    from mydrf.serializers import AuthorSerializer
    from mydrf.serializers import AuthorDatailSerializer
    
    
    class AuthorView(APIView):
        def get(self, request):
            author_qs = models.Author.objects.all()
            author_ser = AuthorSerializer(instance=author_qs, many=True)
            return Response(author_ser.data)
    
        def post(self, request):
            # 将用户详情数据取出来
            author_detail = request.data.pop('detail')
            # 将剩余的用户数据赋值
            author_dict = request.data
            # 先将用户详情进行序列化操作并保存
            author_detail_ser = AuthorDatailSerializer(data=author_detail)
            if author_detail_ser.is_valid():
                author_detail_ser.save()
                # 取出用户详情数据的"nid',并将其添加到用户表的"author_datail"字段
                author_detail_nid = author_detail_ser.data.get("nid")
                author_dict["author_datail"] = author_detail_nid
                # 再将用户信息数据进行序列化并保存
                author_ser = AuthorSerializer(data=author_dict)
                if author_ser.is_valid():
                    author_ser.save()
                    return Response(author_ser.data)
                else:
                    return Response(author_ser.errors)
            else:
                return Response(author_detail_ser.errors)
    
    • urls.py
    path('author/', views.AuthorView.as_view()),
    
    • 效果演示

    12sad

    两张表都新增了数据

    • Author 表

    image-20210414203739414

    • AuthorDeail 表

    image-20210414203753719

    十一.many = True 源码分析

    • 先调用__new__方法

    • 如果 many=True, 生成ListSerializer对象

    • 如果为 many=False,生成Serializer对象

    十二.子序列化

    如果你在序列化器中想重写某个字段 (比如为Book的作者名都加上"xxx"后缀)

    1.可以使用 source 来指定一个方法内存地址

    # models.py 文件中在模型类中书写方法
    def join_xxx(self,obj):
        return obj.name + "xxx"
    
    # serializers.py 文件中对应的Book序列化类中重写字段指定方法
    authors = serializer.CharField(source='join_xxx')
    

    2.可以使用 SerializerMethodField 来操作

    # serializers.py 文件中的Book序列化器书写
    authors = serializers.SerializerMethodField()
    def join_xxx(self,obj):
        return obj.name + "xxx"
    

    3.可以使用子序列化来进行操作

    • 需要创建一个子序列化类

    • 子序列化类必须写在上方, 且只能对外键字段进行重写

    • 使用了子序列化的外键字段就不能再进行反序列化过程

    • 子序列化单个数据需填写 many=False, 多个数据需填写 many=True

    # serializers.py 文件中创建子序列化类,并将子序列化类加入序列化类中
    
    # 子序列化类必须写在上方
    class AuthorSerializer(serializer.ModelSerializer):
        class Meta:
            model = models.Author
            fields = ["name"]
            
    class BookSerializer(serializer.ModelSerializer):
        # 书写子序列化字段
        authors = AuthorSerializer(many=True, read_only=True)
        class Meta:
            model = models.Book
            fields = ["name","price","publish","authors"]
    
  • 相关阅读:
    tomcat 增加压缩设置
    ffmpeg centos6.5上安装(测试 amr 转换为 mp3)
    wkhtmltopdf 安装使用笔记(CentOS6)
    tomcat配置SSL证书(使用startSSL申请到的证书)
    lipo 合并target为Simulator和Device编译的静态库
    aliyun的yum源(国内速度极快)
    OS X 下iso刻录U盘(系统安装启动盘)
    Django学习笔记之数据库-模型的操作
    Django学习笔记之数据库-QuerySet_API
    Django学习笔记之数据库-数据库与模型
  • 原文地址:https://www.cnblogs.com/songhaixing/p/14670486.html
Copyright © 2011-2022 走看看