1. 序列化和反序列化的由来:

  • 前后端分离的核心思想之一,就是两端交互不通过模板语言,只传输需要的数据。因此问题就来了。
  • 在 Django 程序的运行过程中,变量都是存储在服务器的内存中;更要命的是,后端 Django 程序中存储的是 Python 变量,而前端的浏览器中是 Javascript 变量,这两者是无法直接通过你家的网线进行传递和交流的。因此需要规定一个“标准格式”,前后端都根据这个标准格式,对资源进行保存、读取、传输等操作。
  • JSON 就是这种标准格式之一。它很轻量,表示出来就是个字符串,可以直接被几乎所有的语言读取,非常方便。

把变量从内存中变成可存储或传输的过程称之为序列化,反过来把变量内容从序列化的对象重新读到内存里称之为反序列化

2. 创建序列化器

  • 在子应用中,根据**models.py**中的模型类新建**Seriaizer.py**文件,创建了序列化器文件后不能删除**models.py**
  • 所有的序列化器都是**serializers.Serializer**的子类,但是定义字段时都是调用**serializers包**下的字段类。

    2.1 根据数据库模型类定义出相应的序列化器

    已知模型类**BookInfo,HeroInfo**

    1. class BookInfo(models.Model):
    2. btitle = models.CharField(max_length=20, verbose_name='名称')
    3. bpub_date = models.DateField(verbose_name='发布日期')
    4. bread = models.IntegerField(default=0, verbose_name='阅读量')
    5. bcomment = models.IntegerField(default=0, verbose_name='评论量')
    6. is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
    7. class Meta:
    8. db_table = 'tb_books' # 指明数据库表名
    9. verbose_name = '图书' # 在admin站点中显示的名称
    10. verbose_name_plural = verbose_name # 显示的复数名称
    11. def __str__(self):
    12. """定义每个数据对象的显示信息"""
    13. return self.btitle
    1. class HeroInfo(models.Model):
    2. GENDER_CHOICES = (
    3. (0, 'male'),
    4. (1, 'female')
    5. )
    6. hname = models.CharField(max_length=20, verbose_name='名称')
    7. hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
    8. hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
    9. hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 外键
    10. is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
    11. class Meta:
    12. db_table = 'tb_heros'
    13. verbose_name = '英雄'
    14. verbose_name_plural = verbose_name
    15. def __str__(self):
    16. return self.hname

    根据模型类定义出相对应的序列化器类:需要导包:**from rest_framework import serializers**

    1. from rest_framework import serializers
    2. class BookInfoSerializer(serializers.Serializer):
    3. """图书数据序列化器"""
    4. id = serializers.IntegerField(label='ID', read_only=True)
    5. btitle = serializers.CharField(label='名称', max_length=20)
    6. bpub_date = serializers.DateField(label='发布日期', required=False)
    7. bread = serializers.IntegerField(label='阅读量', required=False)
    8. bcomment = serializers.IntegerField(label='评论量', required=False)
    9. image = serializers.ImageField(label='图片', required=False)
    10. # 1V多关联对象字段定义
    11. heroinfo_set = serializers.PrimarKeyRelatedField(label='英雄', read_only=true,many=True)
    1. class HeroInfoSerializers(serializers.Serializer):
    2. GENDER_CHOICES = (
    3. (0, 'male'),
    4. (1, 'female')
    5. )
    6. id = serializers.IntegerField(label="ID", read_only=True)
    7. hname = serializers.CharField(label='名字', max_length=20)
    8. hgender = serializers.ChoiceField(
    9. label='性别', choices=GENDER_CHOICES, required=False)
    10. hcomment = serializers.CharField(
    11. label='描述信息', max_length=200, required=False, allow_null=True)
    12. # 多V1关联对象字段定义
    13. # hbook = serializers.PrimaryKeyRelatedField(label='图书',read_only=True)
    14. # hbook = serializers.HyperlinkedRelatedField(label='图书', read_only=True, view_name='books-detail')
    15. hbook = BookRelateField(read_only=True)

    2.1.1 字段类型

2.1.2 字段通用选项

序列化器类中的字段都含有以下选项:

字段选项 字段选项说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
source
validators 该字段使用的验证器
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
initial
style

2.1.3 元类Meta

3. 使用序列化器

序列化器既可以实现序列化,也可以实现反序列化。

3.1 实例化Serializer类

Serializer的构造方法为:

  1. Serializer(instance=None, data=empty, **kwarg)

说明:

  1. 用于序列化时,将模型类对象赋值给instance参数,无需给data参数赋值。假如instance的值为多个数据对象的字典,则添加

many=True

  1. 用于反序列化时,将要被反序列化的数据传入data参数,不传入instance
  2. 除了**instance****data**参数外,在构造**Serializer**对象时,还可通过**context**参数额外添加数据。
    1. serializer = AccountSerializer(account, context={'request': request})
    2. # 通过context参数附加的数据,可以通过Serializer对象的context属性获取。

    3.2 序列化

    3.2.1 序列化单个数据对象

    1. def get(self,request):
    2. #获取单个数据对象
    3. book = BookInfo.objects.get(id=2)
    4. serializer = BookInfoSerializer(book) #序列化器初始化
    5. # return JsonResponse(ser.data) # 当ser.data是单个数据时,safe可以用默认值
    6. return Response(ser.data)

    2.3.2 序列化多个数据对象

    1. def get(self, request):
    2. # 1、查询所有图书对象
    3. books = BookInfo.objects.all()
    4. # 对序列化器实例化,其中many=True 声明books对象包含多个数据,若返回一个对象,则不需many参数
    5. ser = BookSerialzier(books, many=True) # 也可写为 ser = BookSerialzier(instance=books,many=True)
    6. # ser.data :通过data属性获取序列化后的数据,safe=False:声明data可以为任何被转换为Json格式的对象,默认为True时data类型为字典类型
    7. # return JsonResponse(ser.data, safe=False)——这种是django自带的响应
    8. return Response(ser.data) # 使用DRF的响应对象,内部已经实现了反序列化功能

    3.3 反序列化

  • 使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。分为两步:
  1. 数据校验
  2. 数据保存

版本1:能完成更新数据的类视图函数(views.py) :

  1. def put(self,request,pk): # 函数逻辑:获取单一数据-->验证数据-->更新数据 ,能实现更新数据的功能
  2. # 1、获取前端数据
  3. # 没有使用序列化器时的逻辑
  4. # data = request.body.decode()
  5. # data_dict = json.loads(data)
  6. # 使用了DRF框架
  7. data_dict = request.data
  8. # 2、验证数据
  9. try:
  10. book = BookInfo.objects.get(id=pk) # pk通过路由信息来获取的
  11. except:
  12. return Response({'error': '错误信息'}, status=400)
  13. ser=BookSerialzier(book,data=data_dict)
  14. if ser.is_valid():
  15. # 3、更新数据
  16. ser.save()
  17. # 4、返回结果
  18. return JsonResponse(ser.data)
  19. else:
  20. return Responce(ser.errors,status=status.HTTP_400_BAD_REQUEST)

版本2:只能完成保存功能的类视图函数:

  1. def post(self, request):
  2. 1、获取前端数据
  3. # data = request.body.decode()
  4. # data_dict = json.loads(data)
  5. data_dict = request.data
  6. # 2、验证数据
  7. ser= BookSerialzier(data=data_dict)
  8. ser.is_valid() # 验证方法
  9. # 3、保存数据
  10. ser.save()
  11. # 4、返回结果
  12. return JsonResponse(ser.data)

两个版本的区别:
实例化序列化器过程:只需要保存数据则用: **ser=BookSerialzier(data=data_dict)**;需要更新的话,需要传入模型类对象: **ser=BookSerialzier(book,data=data_dict)**

3.3.1 数据校验

  1. def post(self, request):
  2. # 1、获取前端json表单数据
  3. data = request.body.decode()
  4. data_dict = json.loads(data) #将json 对象数据转换成python字典数据
  5. # 2、验证数据
  6. ser= BookSerialzier(data=data_dict) #通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进行验证
  7. ser.is_valid() # 调用验证方法,成功则返回True,否则返回False。
  8. ser.errors # 获取错误信息,返回字典,包含了字段和字段的错误。验证成功则返回空字典
  9. ser.validated_data #获取数据,此时的数据还只是python字典

3.3.2 验证方法

在定义序列化器时自定义验证方法(Serializer.py)

  1. 在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
  2. 单一字段验证。语法格式:在序列化器中实现方法:**def validate_字段名(self,value)**

    1. # 单一字段验证
    2. def validate_btitle(self, value):
    3. if value == 'python':
    4. raise serializers.ValidationError('书名不能是python')
    5. return value
  3. 多个字段验证:**def validate(self,attrs) # attrs是字典**

    1. # 多个字段验证
    2. def validate(self, attrs):
    3. if attrs['bread'] < attrs['bcomment']:
    4. raise serializers.ValidationError('阅读量大于评论量')
    5. return attrs
  4. 在字段中添加validators选项参数,也可以补充验证行为。Serializers.CharField(…,validators=[ about_django]) ```python def about_django(value): if ‘django’ not in value.lower():

    1. 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)

  1. <a name="IZ2we"></a>
  2. ### 3.3.3 数据保存
  3. 如果在验证成功后,想要基于`**validate_date**`完成数据对象的创建,可以通过实现`**Serializer.py**`文件中的`**create(),update()**`两个方法实现
  4. - create()方法
  5. ```python
  6. class BookInfoSerializer(serializers.Serializer):
  7. """图书数据序列化器"""
  8. ...
  9. def create(self, validated_data): # validated_data是python字典类型,create()方法将字典数据转换为BookInfo对象类型数据
  10. """新建"""
  11. return BookInfo.objects.create(**validated_data) #实现数据对象的创建
  • update()方法

    1. def update(self, instance, validated_data):
    2. """更新,instance为要更新的对象实例"""
    3. instance.btitle = validated_data.get('btitle', instance.btitle)
    4. instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
    5. instance.bread = validated_data.get('bread', instance.bread)
    6. instance.bcomment = validated_data.get('bcomment', instance.bcomment)
    7. instance.save() #将instance对象保存到数据库当中,如果不保存到数据库当中,则无需此操作
    8. return instance

    当执行到ser.save()时,系统会判别调用create()方法还是update()方法,源代码是:

    1. def save(self, **kwargs):
    2. ...
    3. if self.instance is not None:
    4. self.instance = self.update(self.instance, validated_data)
    5. assert self.instance is not None, (
    6. '`update()` did not return an object instance.'
    7. )
    8. else:
    9. self.instance = self.create(validated_data)
    10. assert self.instance is not None, (
    11. '`create()` did not return an object instance.'
    12. )

    4. 序列化器嵌套

    序列化器嵌套:定义一个序列化器时,属性为另一个序列化器实例。 ```python class UserSerializer(serializers.Serializer): email = serializers.EmailField() username = serializers.CharField(max_length=100)

class CommentSerializer(serializers.Serializer): user = UserSerializer() content = serializers.CharField(max_length=200) created = serializers.DateTimeField()

  1. 如果`**UserSerializer**`可以选择接受None值,则应将`**required=False**`标志传递给嵌套序列化程序。
  2. ```python
  3. class CommentSerializer(serializers.Serializer):
  4. user = UserSerializer(required=False) # May be an anonymous user.
  5. content = serializers.CharField(max_length=200)
  6. created = serializers.DateTimeField()

如果嵌套**EditItemSerializer**表示的是项目列表,则应将many=True标志传递给嵌套序列化程序。

  1. class CommentSerializer(serializers.Serializer):
  2. user = UserSerializer(required=False)
  3. edits = EditItemSerializer(many=True) # A nested list of 'edit' items.
  4. content = serializers.CharField(max_length=200)
  5. created = serializers.DateTimeField()

4.1 数据校验

在处理支持反序列化数据的嵌套表示时,嵌套对象的任何错误都将嵌套在嵌套对象的字段名称下。

  1. serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
  2. serializer.is_valid()
  3. # False
  4. serializer.errors
  5. # {'user': {'email': ['Enter a valid e-mail address.']}, 'created': ['This field is required.']}

同样,序列化器实例对象的validated_data属性也将包括嵌套数据结构

4.2 数据保存与更新

在嵌套的序列化器的create()方法与未含有嵌套的序列化器的create()方法不同

  1. class UserSerializer(serializers.ModelSerializer):
  2. profile = ProfileSerializer()
  3. class Meta:
  4. model = User
  5. fields = ['username', 'email', 'profile']
  6. def create(self, validated_data):
  7. profile_data = validated_data.pop('profile')
  8. user = User.objects.create(**validated_data)
  9. Profile.objects.create(user=user, **profile_data)
  10. return user
  11. def update(self, instance, validated_data):
  12. profile_data = validated_data.pop('profile')
  13. # Unless the application properly enforces that this field is
  14. # always set, the following could raise a `DoesNotExist`, which
  15. # would need to be handled.
  16. profile = instance.profile
  17. instance.username = validated_data.get('username', instance.username)
  18. instance.email = validated_data.get('email', instance.email)
  19. instance.save()
  20. profile.is_premium_member = profile_data.get(
  21. 'is_premium_member',
  22. profile.is_premium_member
  23. )
  24. profile.has_support_contract = profile_data.get(
  25. 'has_support_contract',
  26. profile.has_support_contract
  27. )
  28. profile.save()
  29. return instance
  1. class UserSerializer(serializers.ModelSerializer):
  2. class Meta:
  3. model = User
  4. fields = ['username', 'email']
  5. def create(self, validated_data):
  6. return User.objects.create(**validated_data)
  7. def update(self, instance, validated_data):
  8. instance.username = validated_data.get('username', instance.username)
  9. instance.email = validated_data.get('email', instance.email)
  10. instance.save()
  11. return instance

三,超链接模型序列化器

  • HyperlinkedModelSerializer类与 ModelSerializer类相似,只不过它使用超链接来表示关系而不是主键。
  • 默认情况下,序列化器将包含一个 url 字段而不是主键字段。
  • url字段将使用 HyperlinkedIdentityField序列化器字段来表示,并且模型上的任何关系都将使用 HyperlinkedRelatedField序列化器字段来表示。

  • 四,序列化器的继承