django框架之序列化反序列化

Django框架之序列化和反序列化

在使用Django中的DRF框架时,它提供了一个非常重要的功能就是序列化器,比如我们需要将前端接收到处理后的json数据转化为模型,或者向前端返回数据时需要将模型对象转化为json数据,那么这里将模型转化为json的过程称之为序列化,将json数据转化为模型称之为反序列化

定义序列化器

为了得到模型里的字段,序列化器中字段应与模型类中的字段名一致

自定义字段

定义方法

Serializer继承于rest_framework.serializers.Serializer模块

比如我们这里定义一个图书类的序列化器和英雄类的序列化器

图书类序列化器

from rest_framework import serializers

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)
1V多关联对象字段定义
heroinfo_set = serializers.PrimarKeyRelatedField(label='英雄', read_only=true,many=True) 

英雄类序列化器

class HeroInfoSerializers(serializers.Serializer):
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    id = serializers.IntegerField(label="ID", read_only=True)
    hname = serializers.CharField(label='名字', max_length=20)
    hgender = serializers.ChoiceField(
        label='性别', choices=GENDER_CHOICES, required=False)
    hcomment = serializers.CharField(
        label='描述信息', max_length=200, required=False, allow_null=True)
     # 多V1关联对象字段定义
    # hbook = serializers.PrimaryKeyRelatedField(label='图书',read_only=True)
    # hbook = serializers.HyperlinkedRelatedField(label='图书', read_only=True, view_name='books-detail')
    hbook = BookRelateField(read_only=True)


  • 注:
    括号中的read_only参数表示只有序列化时使用,required表示是否必须传入,默认为True

字段类型与选项参数

字段字段构造方式
BooleanFieldBooleanField()
NullBooleanFieldNullBooleanField()
CharFieldCharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailFieldEmailField(max_length=None, min_length=None, allow_blank=False)
RegexFieldRegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugFieldSlugField(maxlength=50, min_length=None, allow_blank=False)
正则字段,验证正则模式 [a-zA-Z0-9-]+
URLFieldURLField(max_length=200, min_length=None, allow_blank=False)
UUIDFieldUUIDField(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”
IPAddressFieldIPAddressField(protocol=‘both’, unpack_ipv4=False, **options)
IntegerFieldIntegerField(max_value=None, min_value=None)
FloatFieldFloatField(max_value=None, min_value=None)
DecimalFieldDecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)
max_digits: 最多位数
decimal_palces: 小数点位置
DateTimeFieldDateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateFieldDateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeFieldTimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationFieldDurationField()
ChoiceFieldChoiceField(choices)
choices与Django的用法相同
MultipleChoiceFieldMultipleChoiceField(choices)
FileFieldFileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageFieldImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListFieldListField(child=, min_length=None, max_length=None)
DictFieldDictField(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页面时,显示的字段帮助提示信息

利用模型类快速定义

1.定义方法:

Serializer继承于rest_framework.serializers.ModelSerializer模块;

此时指明每个字段的序列化类型和选项参数,本身是为后续提供一种验证行为;

2.提供的功能:

  • 基于模块自动生成一系列字段

  • 基于模型类自动为Serializer生成validators

  • 包含默认的create()和update()

同样这里以图书类和英雄类做案例

图书类定义:

class BookInfoSerializer(serializers.ModelSerializer):
    
# 显示指定字段
heroinfo_set =  serializers.PrimaryKeyRelatedField(label='英雄',read_only=True,many=True)

"""图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = '__all__'   #表示展示所有字段
        fields = ('id', 'btitle', 'bpub_date') #表示只显示对应字段
        exclude = ('image',)  # 除image外的所有字段,元组类型
        depth = 1 # 嵌套层级
read_only_fields = ('id', 'bread', 'bcomment') #仅用于序列化输出

英雄类定义

class HeroInfoModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = HeroInfo
        fields = ('id', 'hname', 'hgender', 'hbook')
        depth = 1
extra_kwargs = {
            'bread': {'min_value': 0, 'required': True}},
            'bcomment': {'max_value': 0, 'required': True}},
        }
  • 注:

    • model 指明参照哪个模型类

    • fields指明为模型类的哪些字段生成

    • exclude 指明排除掉哪些字段

    • depth 指明嵌套层级数量

    • 在Meta上方可以指明显示指定字段

    • Extra_kwargs 添加或修改原有字段,优先级高

二、序列化

(一)创建Serializer对象

Serializer对象的构造方式

序列化器名(instance=None,data=empty,**kwary)

  • 注:

    • instance表示模型类对象

    • data用于反序列化传入的数据

    • **wkargs可以传入带名字的参数,其中包括context,该方法可以通过Serializer对象的context属性获取

(二)基本查询

from booktest.models import BookInfo
from booktest.serializers import BookInfoSerializer

#获取单个数据
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)  #序列化器初始化

serializer.data #通过data方法获取数据

#获取多个数据需要用many参数标注
book_qs = BookInfo.objects.all()
serializer = BookInfoSerializer(book_qs, many=True)
serializer.data

关联对象查询

1.一对多关联查询

1:n 图书:英雄

关联模型类名小写_set 作为字段名,同时需要通过many参数标注多个数据

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)

    heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)  # 新增


2.多对一关联查询

n:1 英雄:图书

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

hbook = serializers.PrimaryKeyRelatedField(label='图书', read_only=True)

3.关联字段采用的方法:

  1. PrimaryKeyRelatedField

  2. StringRelatedField

  3. HyperlinkedRelatedField

  4. HyperlinkedRelatedField

  5. 使用关联对象的序列化器

  6. 重写to_representation方法

案例:

hbook = serializers.PrimaryKeyRelatedField(label='图书', read_only=True)
或
hbook = serializers.PrimaryKeyRelatedField(label='图书', queryset=BookInfo.objects.all())
hbook = serializers.StringRelatedField(label='图书')
hbook = serializers.HyperlinkedRelatedField(label='图书', read_only=True, view_name='books-detail')
hbook = serializers.SlugRelatedField(label='图书', read_only=True, slug_field='bpub_date')
hbook = BookInfoSerializer()

class BookRelateField(serializers.RelatedField):
    """自定义用于处理图书的字段"""
    def to_representation(self, value):
        return 'Book: %d %s' % (value.id, value.btitle)

三、反序列化

反序列化分为两步:

  • 数据校验

  • 数据保存

验证数据

使用序列化器进行反序列化之前需要进行验证,验证通过后才可以得到数据从而保存为模型类对象;

在获取序列化数据前,先通过is_valid方法进行验证,它会返回一个布尔值True或者False;

验证失败返回False,此时可以通过errors方法回去错误原因;

验证成功后返回True,此时可以通过validated_data方法获取数据;

校验方法一:

按照定义序列化器是规定的类型进行验证,比如DateField类型必须是时间类型

class BookInfo(models.Model):
    btitle = models.CharField(max_length=20, verbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期', null=True)
……
#----------以上是序列化器中的内容-----------

from booktest.serializers import BookInfoSerializer
data = {'bpub_date': 123}
# 创建序列化器对象
# 序列化第二个参数data用于反序列化,传入字典类型
# 需要用is_valid进行验证,参数raise_exception设置为True 来向前端抛出异常
# 其中属性errors可以查看报错原因,validated_data用于获取数据
serializer = BookInfoSerializer(data=data)
serializer.is_valid(raise_exception=True)  # 返回False, 
serializer.errors
# {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
serializer.validated_data  # {}

校验方法二:

字段选项

比如:

选项参数:

参数名称作用
max_length = 10最大长度不超过10
min_lenght =1最小长度不低于1
allow_blank是否允许为空
trim_whitespace是否截断空白字符
max_value最小值
min_value最大值

检验方法三:

对单独字段进行验证

语法格式:在序列化器中实现方法 def validate_ 字段名(self,value)

注:参数value表示传入的字段值

class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
btitle = models.CharField(max_length=20, verbose_name='名称')
    bpub_date = models.DateField(verbose_name='发布日期', null=True)
    ...

    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()  # False   
serializer.errors
#  {'btitle': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}

校验方法四:

对多个字段进行校验

语法格式:def validate(self,attrs)

注:参数attrs其实就是data字典

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()  # False
s.errors
#  {'non_field_errors': [ErrorDetail(string='阅读量小于评论量', code='invalid')]}

校验方法五

自定义校验方法

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])
……

测试

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

(二) 保存数据

在调用serializer中的save方法时,我们需要手动创建create()和update()方法

在创建序列化对象时,可以通过partial=True来允许部分字段更新

创建新数据

当创建序列化对象时只传入data数据时即为创建新数据,自动调用序列化器中的create方法

在序列化器中定义create方法

注:参数**validated_data其实就是传入的data字典数据

class BookInfoSerializer(serializers.Serializer):
    """图书数据序列化器"""
    ...

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

测试

from db.serializers import BookInfoSerializer
data = {'btitle': '封神演义'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 封神演义>

更新数据

当创建序列化对象时传入实例instance对象和data数据时,即为更新数据

传入两个数据系统会自动调用update方法、

注:instance为要更新的实例对象,validated_data为更新数据

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值