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

    序列化组件介绍

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

    序列化组件的使用

    1、写一个序列化的类,继承Serializer
    2、在类中写要序列化的字段,想序列化哪个字段,就在类中写哪个字段
    3、在视图类中使用,导入--->实例化得到序列化类的对象,把要序列化的对象传入
    4、序列化类的对象.data  是一个字典
    5、把字典返回,如果不使用rest_framework提供的Response,就得使用JsonResponse
    1 写一个序列化的类,继承Serializer
    class BookSerializer(serializers.Serializer):
        # 在这里写要序列化的字段
        # 序列化字段类(有很多,常用的就几个,等同于models中的字段类)
        # 字段类,有很多字段参数()
        name = serializers.CharField()
        price = serializers.IntegerField()
        # publish = serializers.CharField()
    2 在类中写要序列化的字段
        name = serializers.CharField()
        price = serializers.IntegerField()
    3 在视图类中使用(实例化)
        book_list = models.Book.objects.all()                   book_ser=BookSerializer(instance=book_list,many=True)
    4 得到序列化后的数据,返回
        book_ser.data
        
    5 字段参数,source,指定要序列化表中的哪个字段

    source

    1 指定要序列化的字段(数据表中字段)
    publish = serializers.CharField(source='publish.city')
    
    2 用的最多:只有一个字段(也可以跨表)

    SerializerMethodField

    1 用的最多,跨表查(要么是列表,要么是字典)
    publish=serializers.SerializerMethodField()
    def get_publish(self,obj):
            print(obj)
            # return {'name':'sss','city':'sss'}
            return {'name':obj.publish.name,'city':obj.publish.city}

    在模型表中写方法

    # 表模型中写的
    def publish_name(self):
       return {'name':self.publish.name,'city':self.publish.city}
    
    @property
    def author_list(self):
       return [{'name':author.name,'age':author.age,'id':author.nid} for author in self.authors.all()]
    
    #序列化类中
    # publish = serializers.CharField(source='publish_name')
    publish_name = serializers.DictField()
    author_list=serializers.ListField()

    序列化类的字段类型

    有很多 不需要都记住
    只需要记住:
        CharField  IntegerField  DateField...

    序列化字段选项

    max_length                    最大长度
    min_lenght                    最小长度
    allow_blank                    是否允许为空
    trim_whitespace                是否截断空白字符
    max_value                    最小值
    min_value                    最大值

    序列化组件修改数据

    1、写一个序列化的类,继承Serializer
    2、在类中写要反序列化的字段,想反序列化哪个字段,就在类中写哪个字段,字段的属性(max_length...)
    3、在视图类中使用,导入--->实例化得到序列化类的对象,把要修改的对象传入,要修改的数据传入
        book_ser = BookSerializer(book, request.data)
        book_ser = BookSerializer(instance=book, data=request.data)  # 推荐
    4、数据校验
        if book_ser.is_valid():  # 返回True,表示验证通过
    5、如果校验通过,就保存
        book_ser.save()  # 注意不是book.save()  而是序列化器提供的
    6、如果不通过,逻辑自己写
    
    7、如果字段的校验规则不够,可以写钩子函数(局部和全局)
    # 局部钩子
        def validate_price(self, data):  # validated_字段名  接收一个参数
            # 如果价格小于10,就校验不通过
            # print(type(data))  # <class 'str'>
            # print(data)  # 33.66
            if float(data)>10:
                return data
            else:
                # 校验失败,抛异常
                raise ValidationError('价格太低')
    # 全局钩子
        def validate(self,validate_data):
            print(validate_data)
            author = validate_data.get('author')
            publish = validate_data.get('publish')
            if author == publish:
                raise ValidationError('作者名字和出版社一样')
            else:
                return validate_data
            
    8、可以使用字段的author = serializers.CharField(validators=[check_author])  # validators=[]  列表中写函数内存地址
    写一个自定义函数:
    def check_author(data):
        if data.startswith('sb'):
            raise ValidationError('作者名字不能以sb开头')
        else:
            return data
    配置:
        validators=[check_author]

    read_only和write_only

    read_only    表明该字段仅用于序列化输出,默认False,如果设置成True,postman中可以看到该字段,修改时,不需要传该字段
    write_only    表明该字段仅用于反序列化输入,默认False,如果设置成True,postman中看不到该字段,修改时需要传
    
    以下的了解:
    required          表明该字段在反序列化时必须输入,默认True
    default              反序列化时使用的默认值
    allow_null          表明该字段是否允许传入None,默认False
    validators          该字段使用的验证器
    error_messages      包含错误编号与错误信息的字典
    label              用于HTML展示API页面时,显示的字段名称
    help_text          用于HTML展示API页面时,显示的字段帮助提示信息

    查询所有

    # views.py
    # 查询所有
    def get(self, request):
            response_msg = {'status': 100, 'msg': '成功'}
            books = Book.objects.all()
            book_ser = BookSerializer(books, many=True)  # 序列化多条,序列化一条不需要写many=True
            response_msg['data'] = book_ser.data
            return Response(response_msg)
    
    # urls.py
    path('books/', views.BooksView.as_view()),

    新增数据

    # views.py
    class BooksView(APIView):
        # 新增
        def post(self,request):
            response_msg = {'status': 100, 'msg': '成功'}
            # 修改的时候才有instance,新增没有instance,只有data
            book_ser = BookSerializer(data=request.data)
            # book_ser = BookSerializer(request.data)  # 这个按位置传request.data会给instance,就报错了
            # 校验字段
            if book_ser.is_valid():
                book_ser.save()
                response_msg['data'] = book_ser.data
            else:
                response_msg['status'] = 102
                response_msg['msg'] = '数据校验失败'
                response_msg['data'] = book_ser.errors
            return Response(response_msg)
    
    # ser.py  序列化类重写create方法
        # 新增需要重写create()
        def create(self, validated_data):
            instance = Book.objects.create(**validated_data)
            # Book.objects.create(name=validated_data.get('name'))
            return instance
        
    # urls.py
    path('books/', views.BooksView.as_view()),

    删除一个数据

    # views.py:
    class BookView(APIView):
        # 删除
        def delete(self, request, pk):
            ret = Book.objects.filter(pk=pk).delete()
            return Response({'status': 100, 'msg': '删除成功'})
        
    # urls.py:
    re_path('books/(?P<pk>d+)', views.BookView.as_view()),

    模型类序列化器

    # ser.py
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = Book  # 对应上models.py中的模型
            fields = '__all__'
            # fields = ('name','price')  # 只序列化指定的字段
            # exclude = ('name',)  # 跟fields不能都写,写谁,就表示排除谁
    
            # read_only_fields = ('price',)
            # write_only_fields = ('author',)  # 弃用了,使用extra_kwargs
            extra_kwargs = {  # 类似于这种形式name = serializers.CharField(max_length=16, min_length=3)
                'price': {'write_only': True},
            }
            
    # 其他使用一模一样
    # 不需要重写create和update方法了

    源码分析

    many=True实际用途

    # 序列化多条,需要传many=True
    # 
    books = Book.objects.all()
    book = Book.objects.all().first()
    book_ser = BookModelSerializer(books, many=True)  # 序列化多条,序列化一条不需要写many=True
    book_one_ser = BookModelSerializer(book)
    print(type(book_ser))
    # <class 'rest_framework.serializers.ListSerializer'>
    print(type(book_one_ser))
    # <class 'app01.ser.BookModelSerializer'>
    
    
    # 对象的生成 ---> 先调用类的__new__方法,生成空对象
    # 对象=类名(name=lqz),触发类的__init__()
    # 类的__new__方法控制对象的生成
        def __new__(cls, *args, **kwargs):
            if kwargs.pop('many', False):
                return cls.many_init(*args, **kwargs)
            # 没有传many=True,走下面,正常的对象实例化
            return super().__new__(cls, *args, **kwargs)

    serializer高级用法

    # source的使用
        1、可以改字段名字
            xxx = serializers.CharField(source='title')
        2、可以.跨表
            publish = serializers.CharField(source='publish.email')  # book.publish.email
        3、可以执行方法
            pub_date = serializers.CharField(source='test')  # test是Book表模型中的方法
    # SerializerMethodField()的使用
        1、配套一个方法,方法名叫get_字段名,返回值就是要显示的东西
         authors = serializers.SerializerMethodField()
         def get_authors(self, instance):
             # book对象
             authors = instance.authors.all()  # 去除所有作者
             temp = []
             for author in authors:
                 temp.append(author.name)
             return temp  # return什么就是什么

    补充

    1 如果有这个错(把rest_framework在app中注册)

    2 补充自己封装Response对象
    # app01.utils.py:
    class MyResponse():
        def __init__(self):
            self.status = 100
            self.msg = '成功'
    
        @property
        def get_dict(self):
            return self.__dict__
    
    if __name__ == '__main__':
        res = MyResponse()
        res.data = {'name':'lqz'}
        print(res.msg)
        print(res.get_dict)
        
    # views.py:
    # 导入自己写的response类
    from app01.utils import MyResponse
    class BooksView(APIView):
        # 查询所有
        def get(self, request):
            response = MyResponse()
            books = Book.objects.all()
            book_ser = BookSerializer(books, many=True)  # 序列化多条,序列化一条不需要写many=True
            response.data = book_ser.data
            return Response(response.get_dict)
    3 你在实际开发中碰到的问题及如何解决的
    write_only_fields  不能使用了,使用extra_kwargs
    
    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
            extra_kwargs = {
                'price': {'write_only': True},  # 传id报错
            }
  • 相关阅读:
    解决xcode5升级后,Undefined symbols for architecture arm64:问题
    第8章 Foundation Kit介绍
    app 之间发送文件 ios
    iphone怎么检测屏幕是否被点亮 (用UIApplication的Delegate)
    CRM下载对象一直处于Wait状态的原因
    错误消息Customer classification does not exist when downloading
    How to resolve error message Distribution channel is not allowed for sales
    ABAP CCDEF, CCIMP, CCMAC, CCAU, CMXXX这些东东是什么鬼
    有了Debug权限就能干坏事?小心了,你的一举一动尽在系统监控中
    SAP GUI和Windows注册表
  • 原文地址:https://www.cnblogs.com/ZhZhang12138/p/14875800.html
Copyright © 2011-2022 走看看