Django REST framework 序列化

Django REST framework 序列化的使用

基本使用

1)先获取一个图书对象

from book.models import BookInfo

book = BookInfo.objects.get(id=1)


2)创建序列化器实例

from book.serializers import BookInfoSerializer

serializer = BookInfoSerializer(instance=book)

3)获取序列化的数据

serializer.data

结果:
 {'is_delete': False, 'pub_date': '1987-11-11', 'readcount': 58, 'image': None, 'id': 4, 'commentcount': 24, 'name': '雪山飞狐'}

4)如果要被序列化的数据是包含多条数据的查询集QuerySet,可以通过添加many=True参数来补充说明。

book = BookInfo.objects.all()
serializer = BookInfoSerializer(instance=book,many=True)  # 这里更改
serializer.data

[OrderedDict([('id', 3), ('name', '笑傲江湖'), ('pub_date', '1995-12-24'), ('readcount', 28), ('commentcount', 18), ('is_delete', False), ('image', None)]), OrderedDict([('id', 4),....])]

关联对象嵌套序列化

如果需要序列化的数据中包含其他关联对象,则对关联对象数据的序列化需要指明。

例如,在定义英雄数据的序列化器的时候,外键book(即所属图书)字段如何序列化?

咱们先来定义PeopleInfoSerializer除外键字段以外的其他部分

class PeopleInfoSerializer(serializers.Serializer):
    """英雄数据序列化器"""
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='名字', max_length=20)
    gender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
    description = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)

对于关联字段,咱们可以采用以下几种方式:

1)PrimaryKeyRelatedField

此字段将被序列化为关联对象的主键

book = serializers.PrimaryKeyRelatedField(label='图书',read_only=True)
或者
book = serializers.PrimaryKeyRelatedField(label='图书',queryset=BookInfo.objects.all())

指明字段的时候需要包含read_only=Trueu或者queryset参数

  • 包含read_only=True参数时,该字段将只作为序列化输出获取数据的时候使用
  • 包含queryset参数的时候,将被用作反序列化时校验参数使用

2)StringRelatedField

此字段将被序列化为关联对象的字符串表示方式(即____str____方法的返回值)

book = serialzers.StingRelatedField('label'=图书)
# 也可以再把id加上
book_id = serializers.IntegerField()
# 此时获取的就是ID和str返回的值 (这里设置的是name)

3)使用关联对象的序列化器

book = BookInfoSerialzer()

many参数

如果关联的对下那个数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄PeopleInfo可能有多个,此时关联字段类型的指明仍可使用上面的机中方法,只是在声明关联字段的时候,多补充一个many=True参数即可

此处拿PrimaryKeyRelatedField类型来举例,其他相同。

在BookInfoSerializer中添加关联字段:

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='名称', max_length=20)
    pub_date = serializers.DateField(label='发布日期', required=False)
    readcount = serializers.IntegerField(label='阅读量', required=False)
    commentcount = serializers.IntegerField(label='评论量', required=False)
    image = serializers.ImageField(label='图片', required=False)
    peopleinfo_set = serializers.PrimaryKeyRelatedField(many=True) # 这里更改

反序列化的使用

验证

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

在获取反序列化数据之前,必须调用**is_valid()**方法进行验证,验证成功返回True,否则返回False

  • 验证失败,可以通过序列化器对象的errors属性来获取错误信息,返回字典,包含了字段和字段的错误信息
  • 验证成功,可以通过序列化器对象的validated_data属性获取数据。

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

如咱们刚才在上面定义过的BookInfoSerializer

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='名称', max_length=20)
    pub_date = serializers.DateField(label='发布日期', required=False)
    readcount = serializers.IntegerField(label='阅读量', required=False)
    commentcount = serializers.IntegerField(label='评论量', required=False)
    image = serializers.ImageField(label='图片', required=False)

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

# 错误的
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':123}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid()
False
>>> serializer.errors
{'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')], 'name': [ErrorDetail(string='This field is required.', code='required')]}
>>> serializer.validated_data
{}

# 正确的
正确
>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':'2010-1-1','name':'python高级'}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.errors
{}
>>> serializer.validated_data
OrderedDict([('name', 'python高级'), ('pub_date', datetime.date(2010, 1, 1))])

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

>>> from book.serializers import BookInfoSerializer
>>> data = {'pub_date':123}
>>> serializer = BookInfoSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
Traceback (most recent call last):
  File "", line 1, in <module>
  File "/Users/yangjianmei/.virtualenvs/py3_django_1.11/lib/python3.5/site-packages/rest_framework/serializers.py", line 244, in is_valid
    raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')], 'name': [ErrorDetail(string='This field is required.', code='required')]}
>>> serializer.errors
{'pub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')], 'name': [ErrorDetail(string='This field is required.', code='required')]}
>>> serializer.validated_data
{}

还有三种方法,用来补充验证行为:

1)validate_

字段进行验证:

# 方法需要写在BookInfoSerializer序列化器的里面

class BookInfoSerializer(serializers.Serializer):
    '''图书信息序列化器'''
    id = ...
    name = ...
    
    
    def validate_readcount(self,value):
        if value < 0 :
			raise serializers.ValidationError("阅读量不能为负数")
            
         return value       
        

验证的话 还是根据以前的步骤进行验证, 记得把readcount数据改成负数再测试。

2)validate

在序列化器中需要同时对多个字段进行验证的时候,可以使用validate方法:

# 方法需要写在BookInfoSerializer序列化器的里面

class BookInfoSerializer(serializers.Serializer):
    '''图书信息序列化器'''
    id = ...
    name = ...
    
    def validate(self,attrs):
        readcount = attrs.get('readcount')
        commentcount = attrs.get('commentount')
        if commentcount > readcount:
            raise serializers.ValidationError("评论量不能大于阅读量")
            
         return attrs
    
3)validators

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

# 方法需要写在BookInfoSerializer序列化器的里面

class BookInfoSerializer(serializers.Serializer):
    '''图书信息序列化器'''
    
    def custom_validate(self):
        raise serializers.ValidationError('出错!!')
    
    id = ...
    name = serializers.CharField(label='名称',max_length=20,validators=[custom_validate])   # 加参数
    pub_date = ...
    

保存

如果验证成功后,想要基于validated_data完成数据对象的创建,可以通过create()和update()方法来实现。

class BookInfoSerializer(serializers.Serializer):

    """图书数据序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='名称', max_length=20)
    pub_date = serializers.DateField(label='发布日期', required=False)
    readcount = serializers.IntegerField(label='阅读量', required=False)
    commentcount = serializers.IntegerField(label='评论量', required=False)
    image = serializers.ImageField(label='图片', required=False)
    peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)  # 新增


    def create(self, validated_data):
        """新建"""
        return BookInfo.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """更新,instance为要更新的对象实例"""
        instance.name = validated_data.get('name', instance.name)
        instance.pub_date = validated_data.get('pub_date', instance.pub_date)
        instance.readcount = validated_data.get('readcount', instance.readcount)
        instance.commentcount = validated_data.get('commentcount', instance.commentcount)
        instance.save()
        
        # 或者:
        
        instance = BookInfo.objects.filter(id=instance.id).update(**validated_data)
        
        return instance

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

book = serializer.save()

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

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

    serializer.save(owner=request.user)
    
    
  • 默认序列化器必须传递所有required的字段,否则会抛出验证异常,但是 们可以通过使用partial参数来允许部分字段更新

    serializer = BookInfoSerializer(instance=book,data={'name','ok'},partila=True)
    
    
  • 在执行save()方法之前必须先进行is_valid()方法验证。

模型类序列化器ModelSerializer

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serialzer类

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

  • 基于模型类自动生成字段
  • 包含默认的create()和update()的实现

1)定义

class BookInfoModelSerializer(serialzers.ModelSerializer):
    
    class Meta:
        model = BookInfo
        fileds = '__all__'

  • model 指明参照哪个模型类
  • fields 指明为模型类的哪些字段生成

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

>>> from book.serializers import BookInfoSerializer
>>> serializer = BookInfoSerializer()
>>> serializer
BookInfoSerializer():
    id = IntegerField(label='ID', read_only=True)
    name = CharField(label='名称', max_length=20)
    pub_date = DateField(label='发布日期', required=True)
    readcount = IntegerField(label='阅读量', required=True)
    commentcount = IntegerField(label='评论量', required=True)
    image = ImageField(label='图片', required=False)
    peopleinfo_set = PrimaryKeyRelatedField(many=True, read_only=True)

2)指定字段

1) 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如

class BookInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = BookInfo
        fields = '__all__'
2) 使用exclude可以明确排除掉哪些字段

class BookInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = BookInfo
        exclude = ('image',)
3) 显示指明字段,如:

class BookInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = BookInfo
        fields = ('id','name', 'readcount', 'commentcount')
4) 指明只读字段

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

class BookInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = BookInfo
        fields = ('id','name', 'readcount', 'commentcount')
        read_only_fields = ('id', 'readcount', 'commentcount')
3. 添加额外参数
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

class BookInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = BookInfo
        fields = ('id','name', 'readcount', 'commentcount')
        read_only_fields = ('id', 'readcount', 'commentcount')
        extra_kwargs = {
            'readcount': {'min_value': 0, 'required': True},
            'commentcount': {'max_value': 0, 'required': True},
        }

>>> from book.serializers import BookInfoSerializer
>>> serializer = BookInfoSerializer()
>>> serializer
BookInfoSerializer():
    id = IntegerField(label='ID', read_only=True)
    name = CharField(label='名称', max_length=20)
    readcount = IntegerField(label='阅读量', min_value=0, read_only=True)
    commentcount = IntegerField(label='评论量', max_value=0, read_only=True)

你可能感兴趣的:(Django REST framework 序列化)