python

【Django】DRF自定义序列化器、序列化与反序列化冰冷的希望的博客-CSDN博客django 自定义序列化

文章暂存

systemime
2021-06-03
8 min

摘要.

使用 Django 前后端分离开发的情况下,我们经常需要把处理后的数据按照一定的格式(比如说 json)返回,或者把前端传过来的数据进行处理才能进行数据库的 CURD。而 DRF(Django REST Framework)就可以帮忙我解决这个问题,即序列化和反序列化

# 1. 安装 DRF

使用 pip 安装

pip install djangorestframework

配置应用

INSTALLED_APPS = [
    ...
    'rest_framework',
]

# 2. 定义 Serializer

我们新建一个 py 文件专门写序列化类继承 serializers.Serializer,写的字段和约束要在模型类范围之内

models.py

from django.db import models

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)

serializers.py

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)

说明:Serializer 的字段类型几乎与 Models 的一样,记不起来时直接查看 serializers 类即可

选项参数 说明
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 页面时,显示的字段帮助提示信息

# 3. 创建 Serializer 对象

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

说明:

  • 序列化时,instance 传入模型类对象
  • 反序列化时,data 传入被反序列化的数据

# 4. 简单序列化

序列化单个对象

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

book = BookInfo.objects.get(id=2) 
serializer = BookInfoSerializer(book) 

serializer.data 


序列化查询集

books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True) 
serializer.data  

# 5. 关联嵌套序列化(外键)

如果存在外键,在序列化的时候可能是序列化主表或从表两大方向

models.py

class BookInfo(models.Model):
	...
    def __str__(self):
        return self.btitle

class HeroInfo(models.Model):
	...
    hbook = models.ForeignKey(BookInfo, related_name='heros',on_delete=models.CASCADE, verbose_name='图书')  
    def __str__(self):
        return self.hname


# 5.1 序列化主表

serializers.py

class HeroInfoSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    hname = serializers.CharField()
    hgender = serializers.IntegerField()
    hcomment = serializers.CharField()
    is_delete = serializers.BooleanField()

class BookInfoSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    btitle = serializers.CharField()
    bpub_date = serializers.DateField()
    bread = serializers.IntegerField()
    bcomment = serializers.IntegerField()
    is_delete = serializers.BooleanField()
    image = serializers.ImageField()

    序列化主表BookInfo的时候,它的属性heros是关联的从表的多个对象

    关联对象序列化方案一:序列化成关联对象的主键
    heros = serializers.PrimaryKeyRelatedField(
        queryset=HeroInfo.objects.all(), 
        many=True 
    )

    关联对象序列化方案二:序列化成关联对象的__str__方法返回的结果
    heros = serializers.StringRelatedField(many=True)
    
    关联对象序列化方案三:自定义关联对象序列化
    heros = HeroInfoSerializer(many=True)

# 5.1 序列化从表

serializers.py

class BookInfoSerializer(serializers.Serializer):
    btitle = serializers.CharField()
    bpub_date = serializers.DateField()
    bread = serializers.IntegerField()
    bcomment = serializers.IntegerField()
    is_delete = serializers.BooleanField()
    image = serializers.ImageField()

class HeroInfoSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    hname = serializers.CharField()
    hgender = serializers.IntegerField()
    hcomment = serializers.CharField()
    is_delete = serializers.BooleanField()

    代表当前英雄对象(),关联的书本()单一对象
    hbook = serializers.PrimaryKeyRelatedField(
        queryset=BookInfo.objects.all()
    )
    hbook = serializers.StringRelatedField()
    
    hbook = BookInfoSerializer()

三种形式说明
(1)、PrimaryKeyRelatedField(queryset,many)
(2)、StringRelatedField()
(3)、自定义序列化器

# 6. 反序列化

# 6.1 操作步骤

(1)获取有效数据

book_info = {"btitle": "围城", "bpub_date": "1999-9-9"}

(2)实例化序列器对象

bs = BookInfoSerializer(data=book_info, partial=True)

data 是要被校验的数据,partial 为 True 是部分校验,有什么就校验什么

(3)启动校验流程

bs.is_valid()




当调用 is_valid() 方法即开始校验,包括约束条件校验、类型校验、validators 校验、validate_<字段名> 校验、validate 校验,若全部校验通过返回 True,否则返回 False

(4)获得最终结果

若校验成功,查看有效数据
bs.validated_data

若校验失败,查看失败信息
bs.errors

(3)自定义校验之 1:validators

serializers.py


def check_btitle(value):
    if "django" not in value:
        raise serializers.ValidationError("这不是一本关于django的书")

class BookInfoSerializer(serializers.Serializer):
	
    btitle = serializers.CharField(其他校验,validators=[check_btitle] 
    ...

(3)自定义校验之 2:validate_<字段名>

serializers.py

class BookInfoSerializer(serializers.Serializer):
	...
    btitle = serializers.CharField(label='名称',max_length=20,)

    
    def validate_btitle(self, value):
        if "django" not in value:
            raise serializers.ValidationError("这不是一本关于django的书")

        
        return value

(3)自定义校验之 3:validate

serializers.py

class BookInfoSerializer(serializers.Serializer):
	...
    btitle = serializers.CharField(label='名称',max_length=20,)

    def validate(self, attrs):
    	
        btitle = attrs.get('btitle')
        if 'django' not in btitle:
            raise serializers.ValidationError('这不是一本关于django的书')
        
        
        return attrs

第 3 种校验方式最常用,因为它可以对所以字段进行自定义校验

# 6.2 新建和更新操作

前端传过来的数据要写进数据库,可能是新建一条新的数据,也可能只是更新部分字段,在调用 save() 方法的时候会执行新建或更新操作

实例化序列号器对象的时候,如果只传入 data 不传 instance 即为新建,若两者都传即为更新数据

新建和更新的本质是调用我们在序列化器重写的 create() 和 update() 这两个方法

serializers.py

class BookInfoSerializer(serializers.Serializer):
	 btitle = serializers.CharField(label='名称',max_length=20)
	 ...
     def create(self, validated_data):
        instance = BookInfo.objects.create(**validated_data) 
        return instance

    def update(self, instance, validated_data):
        for field,value in validated_data.items():
            
            setattr(instance, field, value)
        instance.save()
        return instance

举例

book_info = {"btitle": "django精通"....}
book = BookInfo.objects.get(pk=6)
bs = BookInfoSerializer(instance=book, data=book_info)
bs.is_valid()

bs.save()

# 7. 补充

# 7.1 PrimaryKeyRelatedField 作用于反序列化
  • PrimaryKeyRelatedField 作用于序列化的时候,把关联对象序列化成主键
  • PrimaryKeyRelatedField 作用与反序列化的时候,把主键反序列化成关联的对象
# 7.2 全更新与部分更新
  • 全更新就是全部字段,必传必校验(默认)
  • 部分更新就是部分字段,必要字段可传可不传,传就会被校验(如更新部分字段操作)

Serializer(instance=模型类对象,data=参数)


Serializer(instance=模型类对象,data=参数,partial=True)

# 7.3 save 方法传递关键字参数

一般情况下是在实例化序列化器的时候就用 data 参数传输待校验的数据,但是后续可能需要指定其他字段,这时候可以在调用 save() 方法的时候传入其他参数
https://blog.csdn.net/qq_39147299/article/details/108691882 https://blog.csdn.net/qq_39147299/article/details/108691882

上次编辑于: 6/5/2021, 11:41:57 AM