Django的DRF(一):前言、简介、Serializer序列化器、ModelSerializer序列化器

一.前言

1.REST接口开发

在开发REST API接口时,视图中做的最主要有三件事:
(1)将请求的数据(如JSON格式)转换为模型类对象
(2)操作数据库
(3)将模型类对象转换为响应的数据(如JSON格式)

2.序列化(Serialization)

(1)维基百科中对于序列化的定义
  序列化(serialization)在计算机科学的资料处理中,是指将数据结构或物件状态转换成可取用格式(例如存成档案,存于缓冲,或经由网络中传送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。依照序列化格式重新获取字节的结果时,可以利用它来产生与原始物件相同语义的副本。对于许多物件,像是使用大量参照的复杂物件,这种序列化重建的过程并不容易。面向对象中的物件序列化,并不概括之前原始物件所关联的函式。这种过程也称为物件编组(marshalling)。从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组, deserialization, unmarshalling)。

(2)序列化在计算机科学中通常有以下定义:
  在数据储存与传送的部分是指将一个对象)存储至一个储存媒介,例如档案或是记亿体缓冲等,或者透过网络传送资料时进行编码的过程,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象)。这程序被应用在不同应用程序之间传送对象),以及服务器将对象)储存到档案或数据库。相反的过程又称为反序列化。
简而言之,我们可以将序列化理解为:
  将程序中的一个数据结构类型转换为其他格式(字典、JSON、XML等),例如将Django中的模型类对象装换为JSON字符串,这个转换过程我们称为序列化。
  反之,将其他格式(字典、JSON、XML等)转换为程序中的数据,例如将JSON字符串转换为Django中的模型类对象,这个过程我们称为反序列化。
  所以在开发REST API时,视图中要频繁的进行序列化与反序列化的编写。
 在这里插入图片描述
 
总结
在开发REST API接口时,我们在视图中需要做的最核心的事是:
(1)将数据库数据序列化为前端所需要的格式,并返回;
(2)将前端发送的数据反序列化为模型类对象,并保存到数据库中。

二.简介

1.概述

Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。

2.环境安装与配置

DRF是以Django扩展应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。(若没有Django环境,需要先创建环境安装Django)
(1)安装DRF

pip install djangorestframework

(2)添加rest_framework
在settings.py的INSTALLED_APPS中添加:

INSTALLED_APPS = [
    ...
    'rest_framework',
]

三.Serializer序列化器

1.定义

(1)定义原则

a. 定义类,继承自Serializer
b. 和模型类,字段名字一样
c. 和模型类,字段类型一样
d. 和模型类,字段选项一样

(2)定义方法

Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。

例如,我们已有了一个数据库模型类BookInfo:

class BookInfo(models.Model):
    btitle = models.CharField(max_length=20, verbose_name='名称')
    bpub_date = models.DateField(verbose_name='发布日期')
    bread = models.IntegerField(default=0, verbose_name='阅读量')
    bcomment = models.IntegerField(default=0, verbose_name='评论量')
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

我们想为这个模型类提供一个序列化器,可以定义如下:

from rest_framework import serializers

class BookInfoSerializer(serializers.Serializer):
    # read_only=True: 只读;  label:字段说明信息
    id = serializers.IntegerField(read_only=True,label='书籍编号')
    btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
    bpub_date = serializers.DateField(label='发布日期')
    bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
    bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
    is_delete = serializers.BooleanField(default=False,label='逻辑删除')

注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。

(3)字段与选项

常用字段类型:

字段字段构造方式
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页面时,显示的字段帮助提示信息

(4)创建Serializer对象

定义好Serializer类后,就可以创建Serializer对象了。
Serializer的构造方法为:

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

说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

serializer = AccountSerializer(account, context={'request': request})

通过context参数附加的数据,可以通过Serializer对象的context属性获取。

2.序列化使用

我们在django shell中来学习序列化器的使用。

python manage.py shell

(1)序列化单个对象

from Book.models import BookInfo
from Book.serializers import BookInfoSerializer

# 1.先获取书籍对象
book = BookInfo.objects.get(id=3)

# 2.创建序列化器,instance:表示要序列化的对象
serializer = BookInfoSerializer(instance=book)

# 3.转换数据
print(serializer.data)

运行结果:

注意:
1)instance=book:表示将book进行序列化操作
2)serializer.data:取到序列化的结果

(2)序列化列表对象

# 1.先获取书籍对象
books = BookInfo.objects.all()
# 2.创建序列化器,instance:表示要序列化的对象,many=True:表示序列化多个对象
serializer = BookInfoSerializer(instance=books,many=True)
# 3.转换数据
print(serializer.data)

运行结果:
在这里插入图片描述

(3)序列化器关联外键

如果需要序列化的数据中包含有其他关联对象,则对关联对象数据的序列化需要指明。
例如,在定义英雄数据的序列化器时,外键hbook(即所属的图书)字段如何序列化?
HeroInfo模型类:

#定义英雄模型类HeroInfo
class HeroInfo(models.Model):
    GENDER_CHOICES = (
        (0, 'male'),
        (1, 'female')
    )
    hname = models.CharField(max_length=20, verbose_name='名称')
    hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
    hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
    hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书')  # 外键
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

我们先定义HeroInfoSerialzier除外键字段外的其他部分:

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)

在shell中运行:

from Book.models import HeroInfo
from Book.serializers import HeroInfoSerializer

# 1.先获取英雄对象
hero = HeroInfo.objects.get(id=6)
# 2.创建序列化器,instance:表示要序列化的对象
serializer = HeroInfoSerializer(instance=hero)
# 3.转换数据
print(serializer.data)

运行结果:
在这里插入图片描述
上面是定义HeroInfoSerialzier除外键字段外的其他部分,那么如果关联到外键呢???
1)PrimaryKeyRelatedField
此字段将被序列化为关联对象的主键

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)

    # 1.关联书籍,主键(PrimaryKeyRelatedField),read_only=True:表示只读,或者设置queryset
    hbook = serializers.PrimaryKeyRelatedField(read_only=True)
    # hbook = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all())

运行结果:
在这里插入图片描述

注意:
指明字段时需要包含read_only=True或者queryset参数:
  包含read_only=True参数时,该字段将不能用作反序列化使用

2) StringRelatedField
此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)

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)
    
    # 2.关联书籍,使用模型类,__str__方法返回值
    hbook = serializers.StringRelatedField(read_only=True)

运行结果:
在这里插入图片描述
3)使用关联对象的序列化器
获取书籍所有信息

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)

    # 3.关联,书籍序列化器
    hbook = BookInfoSerializer()

运行结果:
在这里插入图片描述

(4)序列化器关联many

如果关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄HeroInfo对象可能有多个,此时关联字段类型的指明仍可使用上述几种方式,只是在声明关联字段时,多补充一个many=True参数即可。

在BookInfoSerializer中添加关联字段:

class BookInfoSerializer(serializers.Serializer):
    # read_only=True: 只读;  label:字段说明信息
    id = serializers.IntegerField(read_only=True,label='书籍编号')
    btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
    bpub_date = serializers.DateField(label='发布日期')
    bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
    bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
    is_delete = serializers.BooleanField(default=False,label='逻辑删除')
    # 1.关联英雄,主键,在一方中,输出多方内容的时候加上many=True
    heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True,many=True)

在shell中运行:

from Book.models import BookInfo
from Book.serializers import BookInfoSerializer

# 1.先获取书籍对象
book = BookInfo.objects.get(id=3)
# 2.创建序列化器,instance:表示要序列化的对象
serializer = BookInfoSerializer(instance=book)
# 3.转换数据
print(serializer.data)

运行结果:
在这里插入图片描述
获取英雄名:

class BookInfoSerializer(serializers.Serializer):
    # read_only=True: 只读;  label:字段说明信息
    id = serializers.IntegerField(read_only=True,label='书籍编号')
    btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
    bpub_date = serializers.DateField(label='发布日期')
    bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
    bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
    is_delete = serializers.BooleanField(default=False,label='逻辑删除')

    # 2.关联英雄,__str__返回值
    heroinfo_set = serializers.StringRelatedField(read_only=True,many=True)

运行结果:
在这里插入图片描述

3.反序列化使用

(1)校验

使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。

校验内容:
a)数据类型校验  b)字段选项校验  c)单字段校验(方法) d)多字段校验(方法)  e)自定义校验(方法)
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证

1)数据类型校验
需求:验证bread数据类型
view.py:

# 1.准备数据
book_dict = {
    "btitle":"源自传",
    "bpub_date":"2020-02-20",
    "bread":'yfater',
    "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

# 3.输出
print(serializer.data)

is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。

运行结果:
在这里插入图片描述
上面的是因为bread数据类型不符合,报错
修改正确后,运行结果:
在这里插入图片描述
2)字段选项校验
需求:验证书名字段长度
view.py:

from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    'btitle':'源传',
    'bpub_date':'2020-02-20',
    'bread':10,
    'bcomment':5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

# 3.输出
print(serializer.data)

运行结果:
在这里插入图片描述
上面的是因为书名字段选项不符合,报错
修改正确后,运行结果:
在这里插入图片描述
当我们忽略一些必要字段时:

from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    "btitle":"源自传",
    # "bpub_date":"2020-02-20",
    # "bread":10,
    # "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

# 3.输出
print(serializer.data)

在这里插入图片描述
在序列化器添加required=False:

bpub_date = serializers.DateField(label='发布日期',required=False)

再次运行:
在这里插入图片描述

requred:默认就是True,必须要传递,除非设置了default | false | read_only

3)单字段校验
需求:验证书名中是否包含金瓶
serializers.py:

class BookInfoSerializer(serializers.Serializer):
    # read_only=True: 只读;  label:字段说明信息
    id = serializers.IntegerField(read_only=True,label='书籍编号')
    btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
    bpub_date = serializers.DateField(label='发布日期',required=False)
    bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
    bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
    is_delete = serializers.BooleanField(default=False,label='逻辑删除')

    # 单字段校验
    def validate_btitle(self, value):
        '''
        :param value: 就是传入的btitle
        :return: 
        '''
        # 校验value中的内容
        if '金瓶' not in value:
            raise serializers.ValidationError('书籍名不包含金瓶')
        return value

view.py:

from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    "btitle":"源自传",
    # "bpub_date":"2020-02-20",
    # "bread":10,
    # "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

运行结果:
在这里插入图片描述
修改名字

from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    "btitle":"金瓶2",
    # "bpub_date":"2020-02-20",
    # "bread":10,
    # "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

运行结果:
在这里插入图片描述

注意:
格式固定:
    def vaildate_字段名字(self.value):
       pass

4)多个字段校验
需求:阅读量要大于评论量
serializer.py:

class BookInfoSerializer(serializers.Serializer):
    # read_only=True: 只读;  label:字段说明信息
    id = serializers.IntegerField(read_only=True,label='书籍编号')
    btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
    bpub_date = serializers.DateField(label='发布日期')
    bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
    bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
    is_delete = serializers.BooleanField(default=False,label='逻辑删除')

    # 2.多字段校验
    def validate(self, attrs):
        '''
        :param attrs: 就是外界传进来的,book_dict
        :return:
        '''
        # 获取阅读量,评论量
        bread = attrs['bread']
        bcomment = attrs['bcomment']
        # 判断
        if bcomment > bread:
            raise serializers.ValidationError('评论量大于了阅读量')
        # 返回
        return attrs

views.py:

from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    "btitle":"源自传",
    "bpub_date":"2020-02-20",
    "bread":10,
    "bcomment":50
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

运行结果:
在这里插入图片描述
当评论量大于阅读量就会报错,修改正确:

from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    "btitle":"源自传",
    "bpub_date":"2020-02-20",
    "bread":10,
    "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

运行结果:
在这里插入图片描述

说明:
  单个字段校验时,也可以使用多个字段校验的方法来进行验证
  校验不通过的时候一定要抛出异常

5)自定义校验方法
需求:书籍的年份需要大于19年的
serializers.py:

# 自定义校验方法
def check_bpub_date(value):
    if value.year < 2019:
        raise serializers.ValidationError('书籍的年份需要大于19年的')
    return value

# 定义书籍序列化器
class BookInfoSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True,label='书籍编号')
    btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
    # validators=[check_bpub_date]:将自定义的校验方法作用到字段中
    bpub_date = serializers.DateField(label='发布日期',validators=[check_bpub_date])
    bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
    bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
    is_delete = serializers.BooleanField(default=False,label='逻辑删除')

view.py:

from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    "btitle":"源自传",
    "bpub_date":"2020-02-20",
    "bread":10,
    "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

运行结果:
在这里插入图片描述

(2)入库

如果在验证成功后,想要基于validated_data完成数据对象的创建,可以通过实现create()和update()两个方法来实现。
1)保存对象(create)
view.py:

from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    "btitle":"源自传",
    "bpub_date":"2020-02-20",
    "bread":10,
    "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

# 3.入库(保存数据)
serializer.save()

运行结果:
在这里插入图片描述
报错的原因是,当调用序列化器save方法的时候,必须在序列化器中实现create方法,实现数据入库
serializers.py:

# 自定义校验方法
def check_bpub_date(value):
    if value.year < 2019:
        raise serializers.ValidationError('书籍的年份需要大于19年的')
    return value

# 定义书籍序列化器
class BookInfoSerializer(serializers.Serializer):
    # read_only=True: 只读;  label:字段说明信息
    id = serializers.IntegerField(read_only=True,label='书籍编号')
    btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
    bpub_date = serializers.DateField(label='发布日期',validators=[check_bpub_date])
    bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
    bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
    is_delete = serializers.BooleanField(default=False,label='逻辑删除')

    # 实现create方法
    def create(self, validated_data):
        '''
        :param validated_data: 校验成功之后的数据
        :return: 
        '''
        # 创建book对象,设置属性,入库
        book = BookInfo.objects.create(**validated_data)
        # 返回
        return book

运行结果:
在这里插入图片描述

注意:当使用序列化器调用save方法的时候,执行的就是序列化器中的create方法

2)更新对象(update)
view.py:

from Book.models import BookInfo
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
    "btitle":"源自传2",
    "bpub_date":"2020-03-22",
    "bread":100,
    "bcomment":50
}
book = BookInfo.objects.get(pk=10)
# 2.创建序列化器,校验
serializer = BookInfoSerializer(instance=book,data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)

# 3.入库(保存数据)
serializer.save()

运行结果:
在这里插入图片描述

报错原因是,当在序列化器中传递了两个属性instance,data,同时在使用序列化器调用了save方法,则需要重写序列化器中的update方法。
serializers.py:

# 自定义校验方法
def check_bpub_date(value):
    if value.year < 2019:
        raise serializers.ValidationError('书籍的年份需要大于19年的')
    return value

# 定义书籍序列化器
class BookInfoSerializer(serializers.Serializer):
    # read_only=True: 只读;  label:字段说明信息
    id = serializers.IntegerField(read_only=True,label='书籍编号')
    btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
    bpub_date = serializers.DateField(label='发布日期',validators=[check_bpub_date])
    bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
    bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
    is_delete = serializers.BooleanField(default=False,label='逻辑删除')
  
    # 实现update方法
    def update(self, instance, validated_data):
        '''
        :param instance: 外界传入的book对象
        :param validated_data: 校验成功之后的book_dict数据
        :return: 
        '''
        # 更新数据
        instance.btitle = validated_data['btitle']
        instance.bpub_date = validated_data['bpub_date']
        instance.bread = validated_data['bread']
        instance.bcomment = validated_data['bcomment']
        # 入库
        instance.save()
        # 返回
        return instance

运行结果:
在这里插入图片描述

四.ModelSerializer序列化器

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

1.序列化与反序列化

serializers.py:

# 定义书籍模型类序列化器
from rest_framework import serializers
from Book.models import BookInfo

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        fields = '__all__'  # 生成所有字段

在shell中运行打印:

from Book.serializers import BookModelSerializer
BookModelSerializer()

运行结果:
在这里插入图片描述
由上我们可以知道ModelSerializer可以参考模型类自动生成字段
思考:如果我们想额外添加字段,该怎么操作???

# 定义书籍模型类序列化器
from rest_framework import serializers
from Book.models import BookInfo

class BookModelSerializer(serializers.ModelSerializer):
    mobile = serializers.CharField(max_length=11,min_length=11,label='手机号')
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        fields = '__all__'  # 生成所有字段

运行结果:
在这里插入图片描述
所以ModelSerializer可以参考模型类自动生成字段,也可以手动添加字段

(1)序列化

view.py:

from Book.models import BookInfo
from Book.serializers import BookModelSerializer
# 1.获取模型类对象
book = BookInfo.objects.get(pk=10)
# 2.创建序列化对象
serializer = BookModelSerializer(instance=book)
# 3.输出结果
print(serializer.data)

运行结果:
在这里插入图片描述
之所以报错,是因为刚刚我们手动添加了mobile字段,而原数据库中没有这个字段的数据
解决措施(4种)
a.模型类中添加mobile字段
b.删除序列化器中mobile
c.动态添加一个mobile属性
d.将mobile字段设置为write_only(只写,只进行反序列化)
部分案例:
动态添加一个mobile属性

from Book.models import BookInfo
from Book.serializers import BookModelSerializer
# 1.获取模型类对象
book = BookInfo.objects.get(pk=10)
# 动态添加一个mobile属性
book.mobile = '12121212112'
# 2.创建序列化对象
serializer = BookModelSerializer(instance=book)
# 3.输出结果
print(serializer.data)

运行结果:
在这里插入图片描述
将mobile字段设置为write_only
serializers.py:

from rest_framework import serializers
from Book.models import BookInfo

class BookModelSerializer(serializers.ModelSerializer):
    # 将mobile字段设置为write_only(只写,只进行反序列化)
    mobile = serializers.CharField(max_length=11,min_length=11,label='手机号',write_only=True)
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        fields = '__all__'  # 生成所有字段

运行结果:
在这里插入图片描述

(2)反序列化

1)入库操作
serializer.py:

# 定义书籍模型类序列化器
from rest_framework import serializers
from Book.models import BookInfo

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        fields = '__all__'  # 生成所有字段

views.py:

from Book.serializers import BookModelSerializer
# 准备字典数据
book_dict = {
    'btitle':'鹿鼎记',
    'bpub_date':'2020-9-22',
    'bread':10,
    'bcomment':5
}
# 序列化器对象创建
serializer = BookModelSerializer(data=book_dict)
# 校验,入库
serializer.is_valid(raise_exception=True)
serializer.save()

运行结果:
在这里插入图片描述
由上可发现,我们连create方法都没有创建, 但是却能直接运行成功。
2)更新操作

from Book.serializers import BookModelSerializer
# 准备字典数据,书籍对象
book = BookInfo.objects.get(pk=11)
book_dict = {
    'btitle':'鹿鼎记2',
    'bpub_date':'2020-10-22',
    'bread':199,
    'bcomment':50
}
# 序列化器对象创建
serializer = BookModelSerializer(instance=book,data=book_dict)
# 校验,入库
serializer.is_valid(raise_exception=True)
serializer.save()

运行结果:
在这里插入图片描述
由上可发现,我们update方法也没有创建, 但是却也能直接运行成功。
以上没有创建方法,但都能运行成功,这是因为ModelSerializer序列化器提供了create方法和update方法
ModelSerializer源码
在这里插入图片描述

ModelSerializer序列化器作用:
   1.可以参考模型类自动生成字段,还可以自己编写字段
   2.提供了create方法和update方法

2.指定字段

(1)fields

使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段
serializers.py:

# 定义书籍模型类序列化器
from rest_framework import serializers
from Book.models import BookInfo

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        # 生成指定的字段
        fields = ['id','btitle']

在shell中运行:

from Book.serializers import BookModelSerializer
BookModelSerializer()

运行结果:
在这里插入图片描述

(2)read_only_fields

可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
serializers.py:

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        # 生成指定的字段
        fields = ['id','btitle']
        # 设置只读字段
        read_only_fields = ['btitle']

运行结果:
在这里插入图片描述

(3)exclude

使用exclude可以明确排除掉哪些字段
serializers.py:

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        # 排除指定的字段
        exclude = ['btitle']

运行结果:
在这里插入图片描述

3.添加额外参数

我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
原字段参数:

class BookModelSerializer(serializers.ModelSerializer):
    # mobile = serializers.CharField(max_length=11,min_length=11,label='手机号',write_only=True)
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        fields = '__all__'  # 生成所有字段

运行结果
在这里插入图片描述
现在我们将阅读量和评论量的最大值和最小值进行修改

class BookModelSerializer(serializers.ModelSerializer):
    # mobile = serializers.CharField(max_length=11,min_length=11,label='手机号',write_only=True)
    class Meta:
        model = BookInfo  # 参考模型类生成字段
        fields = '__all__'  # 生成所有字段
        # 给生成的字段添加额外约束
        extra_kwargs = {
            'bread':{
                'max_value':999999,
                'min_value':0
            },
            'bcomment':{
                'max_value':999999,
                'min_value':0
            }
        }

运行结果:
在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值