zoukankan      html  css  js  c++  java
  • DRF序列化器的使用

    序列化器的使用

    序列化器的使用分两个阶段:

    1. 在客户端请求时,使用序列化器可以完成对数据的反序列化。
    2. 在服务器响应时,使用序列化器可以完成对数据的序列化。

    序列化的基本使用

    使用的还是上一篇博文中使用的数据库

    • 先查询出一个学生对象

      from students.models import Student
      
      student = Student.objects.get(id=3)
      
    • 构造序列化器对象

      from .serializers import StudentSerializer
      
      serializer = StudentSerializer(instance=student)
      
    • 获取序列化数据

      通过data属性可以获取序列化后的数据

      serializer.data
      # {'id': 4, 'name': '盖伦', 'age': 18, 'sex': True, 'description': '德玛西亚'}
      
    • 完整视图代码

      from django.views import View
      from students.models import Student
      from .serializers import StudentSerializer
      from django.http.response import JsonResponse
      class StudentRetrieveView(View):
          """使用序列化器序列化转换单个模型数据"""
          def get(self,request,pk):
              # 获取数据
              student = Student.objects.get(pk=pk)
              # 数据转换[序列化过程]
              serializer = StudentSerializer(instance=student)
              print(serializer.data)
              # 响应数据
              return JsonResponse(serializer.data)
      
    • 如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明

      class StudentView(View):    
          """使用序列化器序列化转换多个模型数据"""
          def get(self,request):
              # 获取数据
              student_list = Student.objects.all()
      
              # 转换数据[序列化过程]
              # 如果转换多个模型对象数据,则需要加上many=True
              serializer = StudentSerializer(instance=student_list,many=True)
              print( serializer.data ) # 序列化器转换后的数据
      
              # 响应数据给客户端
              # 返回的json数据,如果是列表,则需要声明safe=False
              return JsonResponse(serializer.data,safe=False)
      

    反序列化

    数据验证

    • 使用序列化器进行反序列化时,首先要对数据进行验证,之后才能获取验证成功的数据或保存成模型类对象。
    • 在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
    • 验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
    • 验证成功,可以通过序列化器对象的validated_data属性获取数据。

    在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。

    新建一个子应用books

    
    python manage.py startapp books
    

    在settings.py中的INSTALLED_APPS中新增books子应用

    INSTALLED_APPS = [
    	# ...
        'ser',
        'unser',
    ]
    

    定义一个图书的模型和序列化器,

    Book模型,代码如下:

    from django.db import models
    class Book(models.Model):
        """图书模型"""
        title = models.CharField(verbose_name='名称', max_length=20)
        pub_date = models.DateField(verbose_name='发布日期')
        read = models.IntegerField(verbose_name='阅读量',default=0)
        comment = models.IntegerField(verbose_name='评论量', null=True, blank=True)
    
        class Meta:
            db_table = "tb_book"
            verbose_name="图书"
            verbose_name_plural=verbose_name
    
        def __str__(self):
            return self.title
    

    执行数据迁移,代码:

    python manage.py makemigrations
    python manage.py migrate
    

    BookSerializer序列化器,代码:

    from rest_framework import serializers
    class BookSerializer(serializers.Serializer):
        """图书数据序列化器"""
        id = serializers.IntegerField(label='ID', read_only=True)
        title = serializers.CharField(label='名称', max_length=20)
        pub_date = serializers.DateField(label='发布日期', required=False)
        read = serializers.IntegerField(label='阅读量', required=False)
        comment = serializers.IntegerField(label='评论量', required=False)
    
    

    通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证

    from book.serializers import BookSerializer
    data = {'pub_date': 123}
    serializer = BookSerializer(data=data)
    serializer.is_valid()  # 返回False
    serializer.errors
    # {'title': [ErrorDetail(string='This field is required.', code='required')], 'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
    serializer.validated_data  # {}
    
    data = {'title': 'python'}
    serializer = BookSerializer(data=data)
    serializer.is_valid()  # True   验证结果返回值
    serializer.errors  # {}  错误信息
    serializer.validated_data  #  OrderedDict([('btitle', 'python')])
    
    

    is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。

    # Return a 400 response if the data was invalid.
    serializer.is_valid(raise_exception=True)
    

    如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:

    validate_字段名

    <field_name>字段进行验证,如

    class BookSerializer(serializers.Serializer):
        """图书数据序列化器"""
        ...
    
        def validate_title(self, value):
            if 'django' not in value.lower():
                raise serializers.ValidationError("图书不是关于Django的")
            return value
    

    测试

    from book.serializers import BookSerializer
    data = {'title': 'python'}
    serializer = BookSerializer(data=data)
    serializer.is_valid()  # False   
    serializer.errors
    #  {'title': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}
    

    validate

    在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证,如

    class BookSerializer(serializers.Serializer):
        """图书序列化器"""
        ...
    
        def validate(self, attrs):
            read = attrs['read']
            comment = attrs['comment']
            if read < comment:
                raise serializers.ValidationError('阅读量小于评论量,不可以通过')
            return attrs
    

    测试

    from book.serializers import BookSerializer
    data = {'title': 'about django', 'read': 10, 'comment': 20}
    s = BookSerializer(data=data)
    s.is_valid()  # False
    s.errors
    #  {'non_field_errors': [ErrorDetail(string='阅读量小于评论量', code='invalid')]}
    

    validators

    在字段中添加validators选项参数,也可以补充验证行为,如

    def about_django(value):
        if 'django' not in value.lower():
            raise serializers.ValidationError("图书不是关于Django的")
    
    class BookSerializer(serializers.Serializer):
        """图书序列化器"""
        id = serializers.IntegerField(label='ID', read_only=True)
        title = serializers.CharField(label='名称', max_length=20, validators=[about_django])
        pub_date = serializers.DateField(label='发布日期', required=False)
        read = serializers.IntegerField(label='阅读量', required=False)
        comment = serializers.IntegerField(label='评论量', required=False)
        image = serializers.ImageField(label='图片', required=False)
    

    测试:

    from book.serializers import BookSerializer
    data = {'title': 'python'}
    serializer = BookSerializer(data=data)
    serializer.is_valid()  # False   
    serializer.errors
    #  {'title': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}
    

    反序列化-保存数据

    前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.

    可以通过实现create()update()两个方法来实现。

    class BookSerializer(serializers.Serializer):
        """图书数据序列化器"""
        ...
    
        def create(self, validated_data):
            """新建"""
            return Book(**validated_data)
    
        def update(self, instance, validated_data):
            """更新,instance为要更新的对象实例"""
            instance.title = validated_data.get('title', instance.title)
            instance.pub_date = validated_data.get('pub_date', instance.pub_date)
            instance.read = validated_data.get('read', instance.read)
            instance.comment = validated_data.get('comment', instance.comment)
            return instance
    

    如果需要在返回数据对象的时候,也将数据保存到数据库中,则可以进行如下修改

    class BookSerializer(serializers.Serializer):
        """图书数据序列化器"""
        ...
    
        def create(self, validated_data):
            """新建"""
            return Book.objects.create(**validated_data)
    
        def update(self, instance, validated_data):
            """更新,instance为要更新的对象实例"""
            instance.title = validated_data.get('title', instance.title)
            instance.pub_date = validated_data.get('pub_date', instance.pub_date)
            instance.read = validated_data.get('read', instance.read)
            instance.comment = validated_data.get('comment', instance.comment)
            instance.save()
            return instance
    

    实现了上述两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了

    book = serializer.save()
    

    如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。

    from .serializers import BookSerializer
    data = {'title': 'python入门指南'}
    serializer = BookSerializer(data=data)
    serializer.is_valid()  # True
    serializer.save()  # <BookInfo: python入门指南>
    
    from .models import Book
    book = Book.objects.get(id=2)
    data = {'title': 'django入门指南'}
    serializer = BookSerializer(book, data=data)
    serializer.is_valid()  # True
    serializer.save()  # <BookInfo: django入门指南>
    book.title  # 'django入门指南'
    

    附加说明

    • 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到

      # request.user 是django中记录当前登录用户的模型对象
      serializer.save(owner=request.user)
      
    • 默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新

      # Update `comment` with partial data
      serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
      

    模型类序列化器

    经过前边的实验,有没有一种疑问,就是我们能不能使用序列化器对应的是Django中的模型类?如果可以的话,就不需要我们对照models模型进行数列化器的设计了。考虑到广大攻城狮的时间成本,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

    ModelSerializer与常规的Serializer相同,但提供了:

    • 基于模型类自动生成一系列字段
    • 基于模型类自动为Serializer生成validators,比如unique_together
    • 包含默认的create()和update()的实现

    定义

    比如我们创建一个BookSerializer

    class BookSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = Book
            fields = '__all__'
    
    • model 指明参照哪个模型类
    • fields 指明为模型类的哪些字段生成

    我们可以在python manage.py shell中查看自动生成的BookSerializer的具体实现

    >>> from booktest.serializers import BookSerializer
    >>> serializer = BookSerializer()
    >>> serializer
    BookSerializer():
        id = IntegerField(label='ID', read_only=True)
        title = CharField(label='名称', max_length=20)
        pub_date = DateField(allow_null=True, label='发布日期', required=False)
        read = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
        comment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)
    

    指定字段

    1. 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
    class BookSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = Book
            fields = "__all__"
    
    1. 使用exclude可以明确排除掉哪些字段
    class BookSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = Book
            exclude = ('pub_date',)
    
    1. 显示指明字段,如:
    class BookSerializer(serializers.ModelSerializer):
        
        class Meta:
            model = Book
            fields = ('id', 'title', 'comment', 'read')
    
    1. 指明只读字段

    可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段

    class BookSerializer(serializers.ModelSerializer):
        """图书序列化器"""
        class Meta:
            model = Book
            fields = ('id', 'title', 'pub_date', 'read', 'comment')
            read_only_fields = ('id', 'read', 'comment')
    

    添加额外参数

    我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

    class BookSerializer(serializers.ModelSerializer):
        """图书序列化器"""
        class Meta:
            model = Book
            fields = ('id', 'title', 'pub_date', 'read', 'comment')
            extra_kwargs = {
                'read': {'min_value': 0, 'required': True},
                'comment': {'min_value': 0, 'required': True},
            }
    
    # BookSerializer():
    #    id = IntegerField(label='ID', read_only=True)
    #    title = CharField(label='名称', max_length=20)
    #    pub_date = DateField(allow_null=True, label='发布日期', required=False)
    #    read = IntegerField(label='阅读量', max_value=2147483647, min_value=0, required=True)
    #    comment = IntegerField(label='评论量', max_value=2147483647, min_value=0, required=True)
    
  • 相关阅读:
    摄影基础知识(二)
    std::bind
    摄影网站汇总
    std::function
    常用路径说明
    摄影基础知识(一)
    JavaScript 箭头函数:适用与不适用场景
    软帝学院:Java实现的5大排序算法
    软帝学院:用Java编写计算器,代码展示!
    windows环境下运行java的脚本
  • 原文地址:https://www.cnblogs.com/jjzz1234/p/11823765.html
Copyright © 2011-2022 走看看