呼和浩特做网站哪家公司好,沈阳网站制作教学,德文网站建设,做自行车网站应该注意什么Python学习之路-DRF基础:Serializer序列化器
序列化器的作用 进行数据的校验 对数据对象进行转换
定义Serializer
定义方法
Django REST framework中的Serializer使用类来定义#xff0c;须继承自rest_framework.serializers.Serializer。
例如#xff0c;我们已有了一…Python学习之路-DRF基础:Serializer序列化器
序列化器的作用 进行数据的校验 对数据对象进行转换
定义Serializer
定义方法
Django REST framework中的Serializer使用类来定义须继承自rest_framework.serializers.Serializer。
例如我们已有了一个数据库模型类BookInfo
class BookInfo(models.Model):btitle models.CharField(max_length20, verbose_name名称)bpub_date models.DateField(verbose_name发布日期, nullTrue)bread models.IntegerField(default0, verbose_name阅读量)bcomment models.IntegerField(default0, verbose_name评论量)image models.ImageField(upload_tobooktest, verbose_name图片, nullTrue)我们想为这个模型类提供一个序列化器可以定义如下
class BookInfoSerializer(serializers.Serializer):图书数据序列化器id serializers.IntegerField(labelID, read_onlyTrue)btitle serializers.CharField(label名称, max_length20)bpub_date serializers.DateField(label发布日期, requiredFalse)bread serializers.IntegerField(label阅读量, requiredFalse)bcomment serializers.IntegerField(label评论量, requiredFalse)image serializers.ImageField(label图片, requiredFalse)**注意serializer不是只能为数据库模型类定义也可以为非数据库模型类的数据定义。**serializer是独立于数据库之外的存在。
字段与选项
常用字段类型
字段字段构造方式BooleanFieldBooleanField()NullBooleanFieldNullBooleanField()CharFieldCharField(max_lengthNone, min_lengthNone, allow_blankFalse, trim_whitespaceTrue)EmailFieldEmailField(max_lengthNone, min_lengthNone, allow_blankFalse)RegexFieldRegexField(regex, max_lengthNone, min_lengthNone, allow_blankFalse)SlugFieldSlugField(maxlength50, min_lengthNone, allow_blankFalse) 正则字段验证正则模式 [a-zA-Z0-9-]URLFieldURLField(max_length200, min_lengthNone, allow_blankFalse)UUIDFieldUUIDField(format‘hex_verbose’) format: 1) hex_verbose 如5ce0e9a5-5ffa-654b-cee0-1238041fb31a 2 hex 如 5ce0e9a55ffa654bcee01238041fb31a 3int - 如: 123456789012312313134124512351145145114 4urn 如: urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31aIPAddressFieldIPAddressField(protocol‘both’, unpack_ipv4False, **options)IntegerFieldIntegerField(max_valueNone, min_valueNone)FloatFieldFloatField(max_valueNone, min_valueNone)DecimalFieldDecimalField(max_digits, decimal_places, coerce_to_stringNone, max_valueNone, min_valueNone) max_digits: 最多位数 decimal_palces: 小数点位置DateTimeFieldDateTimeField(formatapi_settings.DATETIME_FORMAT, input_formatsNone)DateFieldDateField(formatapi_settings.DATE_FORMAT, input_formatsNone)TimeFieldTimeField(formatapi_settings.TIME_FORMAT, input_formatsNone)DurationFieldDurationField()ChoiceFieldChoiceField(choices) choices与Django的用法相同MultipleChoiceFieldMultipleChoiceField(choices)FileFieldFileField(max_lengthNone, allow_empty_fileFalse, use_urlUPLOADED_FILES_USE_URL)ImageFieldImageField(max_lengthNone, allow_empty_fileFalse, use_urlUPLOADED_FILES_USE_URL)ListFieldListField(child, min_lengthNone, max_lengthNone)DictFieldDictField(child)
选项参数
参数名称作用max_length最大长度min_lenght最小长度allow_blank是否允许为空trim_whitespace是否截断空白字符max_value最小值min_value最大值
通用参数
参数名称说明read_only表明该字段仅用于序列化输出默认Falsewrite_only表明该字段仅用于反序列化输入默认Falserequired表明该字段在反序列化时必须输入默认Truedefault反序列化时使用的默认值allow_null表明该字段是否允许传入None默认Falsevalidators该字段使用的验证器error_messages包含错误编号与错误信息的字典label用于HTML展示API页面时显示的字段名称help_text用于HTML展示API页面时显示的字段帮助提示信息
创建Serializer对象
定义好Serializer类后就可以创建Serializer对象了。
Serializer的构造方法为
Serializer(instanceNone, dataempty, **kwarg)说明
1用于序列化时将模型类对象传入instance参数
2用于反序列化时将要被反序列化的数据传入data参数
3除了instance和data参数外在构造Serializer对象时还可通过context参数额外添加数据如
serializer AccountSerializer(account, context{request: request})通过context参数附加的数据可以通过Serializer对象的context属性获取。
序列化使用
简介
我们在django shell中来学习序列化器的使用。
python manage.py shell基本使用 先查询出一个图书对象 from booktest.models import BookInfobook BookInfo.objects.get(id2)构造序列化器对象 from booktest.serializers import BookInfoSerializerserializer BookInfoSerializer(book)获取序列化数据通过data属性可以获取序列化后的数据 serializer.data
# {id: 2, btitle: 天龙八部, bpub_date: 1986-07-24, bread: 36, bcomment: 40, image: None}如果要被序列化的是包含多条数据的查询集QuerySet可以通过添加manyTrue参数补充说明 book_qs BookInfo.objects.all()
serializer BookInfoSerializer(book_qs, manyTrue)
serializer.data
# [OrderedDict([(id, 2), (btitle, 天龙八部), (bpub_date, 1986-07-24), (bread, 36), (bcomment, 40), (image, N]), OrderedDict([(id, 3), (btitle, 笑傲江湖), (bpub_date, 1995-12-24), (bread, 20), (bcomment, 80), (imagene)]), OrderedDict([(id, 4), (btitle, 雪山飞狐), (bpub_date, 1987-11-11), (bread, 58), (bcomment, 24), (ima None)]), OrderedDict([(id, 5), (btitle, 西游记), (bpub_date, 1988-01-01), (bread, 10), (bcomment, 10), (im, booktest/xiyouji.png)])]关联对象嵌套序列化
如果需要序列化的数据中包含有其他关联对象则对关联对象数据的序列化需要指明。
例如在定义英雄数据的序列化器时外键hbook即所属的图书字段如何序列化
我们先定义HeroInfoSerialzier除外键字段外的其他部分
class HeroInfoSerializer(serializers.Serializer):英雄数据序列化器GENDER_CHOICES ((0, male),(1, female))id serializers.IntegerField(labelID, read_onlyTrue)hname serializers.CharField(label名字, max_length20)hgender serializers.ChoiceField(choicesGENDER_CHOICES, label性别, requiredFalse)hcomment serializers.CharField(label描述信息, max_length200, requiredFalse, allow_nullTrue)对于关联字段可以采用以下几种方式 PrimaryKeyRelatedField此字段将被序列化为关联对象的主键。 hbook serializers.PrimaryKeyRelatedField(label图书, read_onlyTrue)
或
hbook serializers.PrimaryKeyRelatedField(label图书, querysetBookInfo.objects.all())指明字段时需要包含read_onlyTrue或者queryset参数 包含read_onlyTrue参数时该字段将不能用作反序列化使用包含queryset参数时将被用作反序列化时参数校验使用 使用效果 from booktest.serializers import HeroInfoSerializer
from booktest.models import HeroInfo
hero HeroInfo.objects.get(id6)
serializer HeroInfoSerializer(hero)
serializer.data
# {id: 6, hname: 乔峰, hgender: 1, hcomment: 降龙十八掌, hbook: 2}StringRelatedField此字段将被序列化为关联对象的字符串表示方式即__str__方法的返回值 hbook serializers.StringRelatedField(label图书)使用效果 {id: 6, hname: 乔峰, hgender: 1, hcomment: 降龙十八掌, hbook: 天龙八部}HyperlinkedRelatedField此字段将被序列化为获取关联对象数据的接口链接 hbook serializers.HyperlinkedRelatedField(label图书, read_onlyTrue, view_namebooks-detail)必须指明view_name参数以便DRF根据视图名称寻找路由进而拼接成完整URL。 使用效果 {id: 6, hname: 乔峰, hgender: 1, hcomment: 降龙十八掌, hbook: http://127.0.0.1:8000/books/2/}我们暂时还没有定义视图此方式不再演示。 SlugRelatedField此字段将被序列化为关联对象的指定字段数据 hbook serializers.SlugRelatedField(label图书, read_onlyTrue, slug_fieldbpub_date)slug_field指明使用关联对象的哪个字段使用效果 {id: 6, hname: 乔峰, hgender: 1, hcomment: 降龙十八掌, hbook: datetime.date(1986, 7, 24)}使用关联对象的序列化器 hbook BookInfoSerializer()使用效果 {id: 6, hname: 乔峰, hgender: 1, hcomment: 降龙十八掌, hbook: OrderedDict([(id, 2), (btitle, 天龙八部)te, 1986-07-24), (bread, 36), (bcomment, 40), (image, None)])}重写to_representation方法 序列化器的每个字段实际都是由该字段类型的to_representation方法决定格式的可以通过重写该方法来决定格式。 注意to_representations方法不仅局限在控制关联对象格式上适用于各个序列化器字段类型。 自定义一个新的关联字段 class BookRelateField(serializers.RelatedField):自定义用于处理图书的字段def to_representation(self, value):return Book: %d %s % (value.id, value.btitle)指明hbook为BookRelateField类型 hbook BookRelateField(read_onlyTrue)使用效果 {id: 6, hname: 乔峰, hgender: 1, hcomment: 降龙十八掌, hbook: Book: 2 天龙八部}many参数
如果关联的对象数据不是只有一个而是包含多个数据如想序列化图书BookInfo数据每个BookInfo对象关联的英雄HeroInfo对象可能有多个此时关联字段类型的指明仍可使用上述几种方式只是在声明关联字段时多补充一个manyTrue参数即可。
此处仅拿PrimaryKeyRelatedField类型来举例其他相同。
在BookInfoSerializer中添加关联字段
class BookInfoSerializer(serializers.Serializer):图书数据序列化器id serializers.IntegerField(labelID, read_onlyTrue)btitle serializers.CharField(label名称, max_length20)bpub_date serializers.DateField(label发布日期, requiredFalse)bread serializers.IntegerField(label阅读量, requiredFalse)bcomment serializers.IntegerField(label评论量, requiredFalse)image serializers.ImageField(label图片, requiredFalse)heroinfo_set serializers.PrimaryKeyRelatedField(read_onlyTrue, manyTrue) # 新增使用效果
from booktest.serializers import BookInfoSerializer
from booktest.models import BookInfo
book BookInfo.objects.get(id2)
serializer BookInfoSerializer(book)
serializer.data
# {id: 2, btitle: 天龙八部, bpub_date: 1986-07-24, bread: 36, bcomment: 40, image: None, heroinfo_set: [6,8, 9]}反序列化使用
验证
使用序列化器进行反序列化时需要对数据进行验证后才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前必须调用**is_valid()**方法进行验证验证成功返回True否则返回False。
验证失败可以通过序列化器对象的errors属性获取错误信息返回字典包含了字段和字段的错误。如果是非字段错误可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时指明每个字段的序列化类型和选项参数本身就是一种验证行为。
如我们前面定义过的BookInfoSerializer
class BookInfoSerializer(serializers.Serializer):图书数据序列化器id serializers.IntegerField(labelID, read_onlyTrue)btitle serializers.CharField(label名称, max_length20)bpub_date serializers.DateField(label发布日期, requiredFalse)bread serializers.IntegerField(label阅读量, requiredFalse)bcomment serializers.IntegerField(label评论量, requiredFalse)image serializers.ImageField(label图片, requiredFalse)通过构造序列化器对象并将要反序列化的数据传递给data构造参数进而进行验证
from booktest.serializers import BookInfoSerializer
data {bpub_date: 123}
serializer BookInfoSerializer(datadata)
serializer.is_valid() # 返回False
serializer.errors
# {btitle: [ErrorDetail(stringThis field is required., coderequired)], bpub_date: [ErrorDetail(stringDate has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]., codeinvalid)]}
serializer.validated_data # {}data {btitle: python}
serializer BookInfoSerializer(datadata)
serializer.is_valid() # True
serializer.errors # {}
serializer.validated_data # OrderedDict([(btitle, python)])is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError可以通过传递raise_exceptionTrue参数开启REST framework接收到此异常会向前端返回HTTP 400 Bad Request响应。
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exceptionTrue)如果觉得这些还不够需要再补充定义验证行为可以使用以下三种方法 validate_field_name对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(datadata)
serializer.is_valid() # False
serializer.errors
# {btitle: [ErrorDetail(string图书不是关于Django的, codeinvalid)]}validate在序列化器中需要同时对多个字段进行比较验证时可以定义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(datadata)
s.is_valid() # False
s.errors
# {non_field_errors: [ErrorDetail(string阅读量小于评论量, codeinvalid)]}validators在字段中添加validators选项参数也可以补充验证行为如 def about_django(value):if django not in value.lower():raise serializers.ValidationError(图书不是关于Django的)class BookInfoSerializer(serializers.Serializer):图书数据序列化器id serializers.IntegerField(labelID, read_onlyTrue)btitle serializers.CharField(label名称, max_length20, validators[about_django])bpub_date serializers.DateField(label发布日期, requiredFalse)bread serializers.IntegerField(label阅读量, requiredFalse)bcomment serializers.IntegerField(label评论量, requiredFalse)image serializers.ImageField(label图片, requiredFalse)测试 from booktest.serializers import BookInfoSerializer
data {btitle: python}
serializer BookInfoSerializer(datadata)
serializer.is_valid() # False
serializer.errors
# {btitle: [ErrorDetail(string图书不是关于Django的, codeinvalid)]}REST framework提供的validators: UniqueValidator 单字段唯一如 from rest_framework.validators import UniqueValidatorslug SlugField(max_length100,validators[UniqueValidator(querysetBlogPost.objects.all())]
)UniqueTogetherValidation 联合唯一如 from rest_framework.validators import UniqueTogetherValidatorclass ExampleSerializer(serializers.Serializer):# ...class Meta:validators [UniqueTogetherValidator(querysetToDoItem.objects.all(),fields(list, position))]保存
如果在验证成功后想要基于validated_data完成数据对象的创建可以通过实现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()方法返回一个数据对象实例了
book serializer.save()如果创建序列化器对象的时候没有传递instance实例则调用save()方法的时候create()被调用相反如果传递了instance实例则调用save()方法的时候update()被调用。
from db.serializers import BookInfoSerializer
data {btitle: 封神演义}
serializer BookInfoSerializer(datadata)
serializer.is_valid() # True
serializer.save() # BookInfo: 封神演义from db.models import BookInfo
book BookInfo.objects.get(id2)
data {btitle: 倚天剑}
serializer BookInfoSerializer(book, datadata)
serializer.is_valid() # True
serializer.save() # BookInfo: 倚天剑
book.btitle # 倚天剑两点说明 在对序列化器进行save()保存时可以额外传递数据这些数据可以在create()和update()中的validated_data参数获取到 serializer.save(ownerrequest.user)默认序列化器必须传递所有required的字段否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新 # Update comment with partial data
serializer CommentSerializer(comment, data{content: ufoo bar}, partialTrue)模型类序列化器ModelSerializer
简介
如果我们想要使用序列化器对应的是Django的模型类DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
ModelSerializer与常规的Serializer相同但提供了
基于模型类自动生成一系列字段基于模型类自动为Serializer生成validators比如unique_together包含默认的create()和update()的实现
定义
比如我们创建一个BookInfoSerializer
class BookInfoSerializer(serializers.ModelSerializer):图书数据序列化器class Meta:model BookInfofields __all__model 指明参照哪个模型类fields 指明为模型类的哪些字段生成
我们可以在python manage.py shell中查看自动生成的BookInfoSerializer的具体实现 from booktest.serializers import BookInfoSerializerserializer BookInfoSerializer()serializer
BookInfoSerializer():id IntegerField(labelID, read_onlyTrue)btitle CharField(label名称, max_length20)bpub_date DateField(allow_nullTrue, label发布日期, requiredFalse)bread IntegerField(label阅读量, max_value2147483647, min_value-2147483648, requiredFalse)bcomment IntegerField(label评论量, max_value2147483647, min_value-2147483648, requiredFalse)image ImageField(allow_nullTrue, label图片, max_length100, requiredFalse)指定字段 使用fields来明确字段__all__表名包含所有字段也可以写明具体哪些字段如 class BookInfoSerializer(serializers.ModelSerializer):图书数据序列化器class Meta:model BookInfofields (id, btitle, bpub_date)使用exclude可以明确排除掉哪些字段 class BookInfoSerializer(serializers.ModelSerializer):图书数据序列化器class Meta:model BookInfoexclude (image,)默认ModelSerializer使用主键作为关联字段但是我们可以使用depth来简单的生成嵌套表示depth应该是整数表明嵌套的层级数量。如 class HeroInfoSerializer2(serializers.ModelSerializer):class Meta:model HeroInfofields __all__depth 1形成的序列化器如下 HeroInfoSerializer():id IntegerField(labelID, read_onlyTrue)hname CharField(label名称, max_length20)hgender ChoiceField(choices((0, male), (1, female)), label性别, requiredFalse, validators[django.core.valators.MinValueValidator object, django.core.validators.MaxValueValidator object])hcomment CharField(allow_nullTrue, label描述信息, max_length200, requiredFalse)hbook NestedSerializer(read_onlyTrue):id IntegerField(labelID, read_onlyTrue)btitle CharField(label名称, max_length20)bpub_date DateField(allow_nullTrue, label发布日期, requiredFalse)bread IntegerField(label阅读量, max_value2147483647, min_value-2147483648, requiredFalse)bcomment IntegerField(label评论量, max_value2147483647, min_value-2147483648, requiredFalse)image ImageField(allow_nullTrue, label图片, max_length100, requiredFalse)显示指明字段如 class HeroInfoSerializer(serializers.ModelSerializer):hbook BookInfoSerializer()class Meta:model HeroInfofields (id, hname, hgender, hcomment, hbook)指明只读字段可以通过read_only_fields指明只读字段即仅用于序列化输出的字段 class BookInfoSerializer(serializers.ModelSerializer):图书数据序列化器class Meta:model BookInfofields (id, btitle, bpub_date bread, bcomment)read_only_fields (id, bread, bcomment)添加额外参数
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
class BookInfoSerializer(serializers.ModelSerializer):图书数据序列化器class Meta:model BookInfofields (id, btitle, bpub_date, bread, bcomment)extra_kwargs {bread: {min_value: 0, required: True},bcomment: {min_value: 0, required: True},}# BookInfoSerializer():
# id IntegerField(labelID, read_onlyTrue)
# btitle CharField(label名称, max_length20)
# bpub_date DateField(allow_nullTrue, label发布日期, requiredFalse)
# bread IntegerField(label阅读量, max_value2147483647, min_value0, requiredTrue)
# bcomment IntegerField(label评论量, max_value2147483647, min_value0, requiredTrue)