Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
例如,我们已有了一个数据库模型类BookInfo
| class BookInfo(models.Model): |
| btitle = models.CharField(max_length=20, verbose_name='名称') |
| bpub_date = models.DateField(verbose_name='发布日期', null=True) |
| bread = models.IntegerField(default=0, verbose_name='阅读量') |
| bcomment = models.IntegerField(default=0, verbose_name='评论量') |
| image = models.ImageField(upload_to='booktest', verbose_name='图片', null=True) |
我们想为这个模型类提供一个序列化器,可以定义如下:
| class BookInfoSerializer(serializers.Serializer): |
| """图书数据序列化器""" |
| id = serializers.IntegerField(label='ID', read_only=True) |
| btitle = serializers.CharField(label='名称', max_length=20) |
| bpub_date = serializers.DateField(label='发布日期', required=False) |
| bread = serializers.IntegerField(label='阅读量', required=False) |
| bcomment = serializers.IntegerField(label='评论量', required=False) |
| image = serializers.ImageField(label='图片', required=False) |
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。
常用字段类型:
字段 |
字段构造方式 |
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(max_length=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=) |
选项参数:
参数名称 |
作用 |
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 |
包含错误编号与错误信息的字典 |
label |
用于HTML展示API页面时,显示的字段名称 |
help_text |
用于HTML展示API页面时,显示的字段帮助提示信息 |
定义好Serializer类后,就可以创建Serializer对象了。
Serializer的构造方法为:
| Serializer(instance=None, data=empty, **kwarg) |
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
| serializer = AccountSerializer(account, context={'request': request}) |
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
- 使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
- 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
- 序列化器的字段声明类似于我们前面使用过的表单系统。
- 开发restful api时,序列化器会帮我们把模型数据转换成字典.
- drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.
序列化器的使用分两个阶段:
- 在客户端请求时,使用序列化器可以完成对数据的反序列化。
- 在服务器响应时,使用序列化器可以完成对数据的序列化。
1) 先查询出一个图书对象
| from booktest.models import BookInfo |
| |
| book = BookInfo.objects.get(id=2) |
2) 构造序列化器对象
| from booktest.serializers import BookInfoSerializer |
| |
| serializer = BookInfoSerializer(book) |
3)获取序列化数据
通过data属性可以获取序列化后的数据
4)如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明
| book_qs = BookInfo.objects.all() |
| serializer = BookInfoSerializer(book_qs, many=True) |
| serializer.data |
| |
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
如我们前面定义过的BookInfoSerializer
| class BookInfoSerializer(serializers.Serializer): |
| """图书数据序列化器""" |
| id = serializers.IntegerField(label='ID', read_only=True) |
| btitle = serializers.CharField(label='名称', max_length=20) |
| bpub_date = serializers.DateField(label='发布日期', required=False) |
| bread = serializers.IntegerField(label='阅读量', required=False) |
| bcomment = serializers.IntegerField(label='评论量', required=False) |
| image = serializers.ImageField(label='图片', required=False) |
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
| from booktest.serializers import BookInfoSerializer |
| data = {'bpub_date': 123} |
| serializer = BookInfoSerializer(data=data) |
| serializer.is_valid() |
| serializer.errors |
| |
| serializer.validated_data |
| |
| data = {'btitle': 'python'} |
| serializer = BookInfoSerializer(data=data) |
| serializer.is_valid() |
| serializer.errors |
| serializer.validated_data |
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
| |
| serializer.is_valid(raise_exception=True) |
如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:
对<field_name>
字段进行验证,如
| class BookInfoSerializer(serializers.Serializer): |
| """图书数据序列化器""" |
| ... |
| |
| def validate_btitle(self, value): |
| if 'django' not in value.lower(): |
| raise serializers.ValidationError("图书不是关于Django的") |
| return value |
测试
| from booktest.serializers import BookInfoSerializer |
| data = {'btitle': 'python'} |
| serializer = BookInfoSerializer(data=data) |
| serializer.is_valid() |
| serializer.errors |
| |
在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证,如
| class BookInfoSerializer(serializers.Serializer): |
| """图书数据序列化器""" |
| ... |
| |
| def validate(self, attrs): |
| bread = attrs['bread'] |
| bcomment = attrs['bcomment'] |
| if bread < bcomment: |
| raise serializers.ValidationError('阅读量小于评论量') |
| return attrs |
测试
| from booktest.serializers import BookInfoSerializer |
| data = {'btitle': 'about django', 'bread': 10, 'bcomment': 20} |
| s = BookInfoSerializer(data=data) |
| s.is_valid() |
| s.errors |
| |
在字段中添加validators选项参数,也可以补充验证行为,如
| def about_django(value): |
| if 'django' not in value.lower(): |
| raise serializers.ValidationError("图书不是关于Django的") |
| |
| class BookInfoSerializer(serializers.Serializer): |
| """图书数据序列化器""" |
| id = serializers.IntegerField(label='ID', read_only=True) |
| btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django]) |
| bpub_date = serializers.DateField(label='发布日期', required=False) |
| bread = serializers.IntegerField(label='阅读量', required=False) |
| bcomment = serializers.IntegerField(label='评论量', required=False) |
| image = serializers.ImageField(label='图片', required=False) |
测试:
| from booktest.serializers import BookInfoSerializer |
| data = {'btitle': 'python'} |
| serializer = BookInfoSerializer(data=data) |
| serializer.is_valid() |
| serializer.errors |
| |
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.
可以通过实现create()和update()两个方法来实现。
| class BookInfoSerializer(serializers.Serializer): |
| """图书数据序列化器""" |
| ... |
| |
| def create(self, validated_data): |
| """新建""" |
| return BookInfo(**validated_data) |
| |
| def update(self, instance, validated_data): |
| """更新,instance为要更新的对象实例""" |
| instance.btitle = validated_data.get('btitle', instance.btitle) |
| instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date) |
| instance.bread = validated_data.get('bread', instance.bread) |
| instance.bcomment = validated_data.get('bcomment', instance.bcomment) |
| return instance |
如果需要在返回数据对象的时候,也将数据保存到数据库中,则可以进行如下修改
| class BookInfoSerializer(serializers.Serializer): |
| """图书数据序列化器""" |
| ... |
| |
| def create(self, validated_data): |
| """新建""" |
| return BookInfo.objects.create(**validated_data) |
| |
| def update(self, instance, validated_data): |
| """更新,instance为要更新的对象实例""" |
| instance.btitle = validated_data.get('btitle', instance.btitle) |
| instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date) |
| instance.bread = validated_data.get('bread', instance.bread) |
| instance.bcomment = validated_data.get('bcomment', instance.bcomment) |
| instance.save() |
| return instance |
实现了上述两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了
如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。
| from db.serializers import BookInfoSerializer |
| data = {'btitle': '封神演义'} |
| serializer = BookInfoSerializer(data=data) |
| serializer.is_valid() |
| serializer.save() |
| |
| from db.models import BookInfo |
| book = BookInfo.objects.get(id=2) |
| data = {'btitle': '倚天剑'} |
| serializer = BookInfoSerializer(book, data=data) |
| serializer.is_valid() |
| serializer.save() |
| book.btitle |
1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到
| |
| serializer.save(owner=request.user) |
2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新
| |
| serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True) |