DRF中序列化与反序列化
1.序列化
序列化:展示特殊的数据(choices,ForeignKey,ManyToMany)可以使用的三种方法
1.source方法(常用于ForeignKey,与choices获取对应的中文)
user__avatar = serializers.CharField(source='user.avatar',read_only=True) # user__avatar命名可以自定义
user_id = serializers.CharField(source='user.id',read_only=True)
user_nickname = serializers.CharField(source='user.nickname',read_only=True)
特例:对于choices get_字段名_display 获取choices对应的中文
auction_start_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S')
auction_end_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S')
#不加read_only=True,也只是序列化,反序列化不会影响
即:对数据进行序列化,返回给前端,数据字段名称可自定义,通过source指定对应的字段,read_only 指定该表中字段不进行校验,而只进行序列化 通常为ForeignKey
注:使用read_only=True后,仅对数据进行序列化
2.SerializerMethodField:定义钩子方法。(一对多,多对多推荐)
user = serializers.SerializerMethodField() #新增数据库不存在字段或已有字段自定义命名
.....
def get_user(self, obj):
if not obj.user:
return
return model_to_dict(obj.user, fields=['id', 'nickname', 'avatar'])
serializers.SerializerMethodField和钩子方法结合,可以实现对ModelSerializer类的一些字段进行二次加工,将数据序列化返回给前端
注:只有序列化时回使用,反序列化时不会影响
3.序列化嵌套
# 简单省事可全部返回
class GoodsCategorySerializers(serializers.ModelSerializer):
class Meta:
model = GoodsCategory
fields = "__all__"
class GoodsListSerializers(serializers.ModelSerializer):
category = GoodsCategorySerializers()
class Meta:
model = Goods
fields = "__all__"
默认情况下,嵌套序列化器是只读的( !!!严重怀疑官网写错了,只读的话嵌套序列化必须指定read_only=true,不然反序列化的时候提示该序列化需必填),本人亲测,若不对请指正,谢谢
如果希望支持对嵌套序列化器字段的写操作,则需要创建create()和/或update()方法,以便显式指定应该如何保存子关系。
如果要实现可写,就要去掉read_only=true,同时添加create方法,如下:
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('order', 'title', 'duration')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
2.反序列化
def validate_字段名(): # 表单校验
# 对前端请求数据进行校验,serializers中使用
# value 可为请求的model对象,通过value.xx 获取对应的字段
def validate_coupon(self, value):
user_object = self.context['request'].user
coupon_obj = models.Coupon.objects.filter(id=value.id).first()
if coupon_obj.deleted != 0:
raise exceptions.ValidationError(detail='已删除')
if coupon_obj.status != 2:
raise exceptions.ValidationError(detail='未开始或已结束')
exists = models.UserCoupon.objects.filter(user=user_object, coupon=coupon_obj).exists()
if exists:
raise exceptions.ValidationError(detail='已领取优惠券')
if coupon_obj.count - coupon_obj.apply_count <= 0:
raise exceptions.ValidationError(detail='优惠券已经申请完')
return value
auction_id = serializers.IntegerField(label='拍卖ID')
def validate_auction_id(self, value):
user_object = self.context['request'].user
exists = models.DepositRecord.objects.filter(user=user_object, auction_id=value, item__isnull=True).exists()
if exists:
raise exceptions.ValidationError(detail='已支付过全场保证金')
return value
# 这里的value即为获取的请求具体的字段
3.终极大法,分开写serializer_class
# 视图函数中分开写serializer_class,序列化是一个serializer_class.反序列化也是一个serializer_class
def get_serializer_class(self):
if self.action == "list":
return CouponSerializer
else:
return CouponCreatSerializer
单表序列化总结
1. 序列化与反序列化功能可以整合到一个类,该类继承ModelSerializer
2. 继承ModelSerializer类的资源序列化类,内部包含三部分
Meta字类、局部钩子、全局钩子
注:create和update方法ModelSerializer已经重写了,使用时不需要重写
3. 在Meta字类中:
用model来绑定关联的Model类
用fields来设置所有的序列化反序列化字段
用extra_kwargs来设置系统的校验规则
4. 重要的字段校验规则:
read_only校验规则,代表该字段只参与序列化
write_only校验规则,代表该字段只参与反序列化
required校验规则,代表该字段在反序列化时是必填(True)还是选填(False),不能和read_only一起使用(规则冲突)
规则细节:
如果一个字段有默认值或可以为空,没设置required,默认为False,反之为True
如果一个Model字段既没有设置read_only也没有设置write_only,该字段默认参与序列化及反序列化
5. 自定义序列化字段:在Model类中,定义方法属性(返回特殊值,还可以完成连表操作),在序列化类的fields属性中可以选择性插拔
6. 自定义反序列化字段:在Serializer类中,自定义校验字段,校验规则也只能在声明字段时设置,自定义的反序列化字段(pwd),必须设置write_only为True
"""
\