django-Serializer序列化器的简单使用

使用serializer之前要先进行环境的安装和配置

  • 首先安装DRF
pip install djangorestframework

# DRF是以Django扩展应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。
#(若没有Django环境,需要先创建环境安装Django)
# DRF需要以下依赖:
# Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
# Django (1.10, 1.11, 2.0)
  • 在django项目中注册rest_framework应用
    在settings.py的INSTALLED_APPS中添加'rest_framework'
INSTALLED_APPS = [
    ...
    'rest_framework',
]

在django项目中使用serializer序列化器

我们在django项目中新建一个子应用(bookapp)进行serializer序列化器的使用介绍(自己完成子应用的注册和路由配置):

我们在models.py中定义一个书籍模型类BookInfo和英雄模型类HeroInfo:

# 数据导入见附录
class BookInfo(models.Model):
    btitle = models.CharField(max_length=20,verbose_name="书籍名称")
    bpub_date = models.DateField(null=True,verbose_name="发布日期")
    bread = models.IntegerField(default=0,verbose_name="阅读量")
    bcomment = models.IntegerField(default=0,verbose_name="评论量")
    is_delete = models.BooleanField(default=False,verbose_name="逻辑删除")

    class Meta:
        db_table = "tb_books"  # 表在数据库的名字
        verbose_name = "图书"  #在admin站点显示名称
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.btitle


class HeroInfo(models.Model):

    GENDER_CHOICES = (
        (0, 'female'),
        (1, 'male')
    )
    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='逻辑删除')

    class Meta:
        db_table = 'tb_heros'
        verbose_name = '英雄'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.hname

我们为这两个模型类提供序列化器,可以定义如下:
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。

from rest_framework import serializers

class BookInfoSerializer(serializers.Serializer):
    btitle = serializers.CharField(min_length=3,max_length=20)
    bpub_date = serializers.DateField()
    bread = serializers.IntegerField(read_only=True)
    bcomment = serializers.IntegerField(write_only=True)


class HeroInfoSerializer(serializers.Serializer):
    hname = serializers.CharField()
    hcomment = serializers.CharField()

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

字段与选项的说明

常用字段类型

字段 字段构造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(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"
IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)
max_digits: 最多位数
decimal_palces: 小数点位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices)
choices与Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(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页面时,显示的字段帮助提示信息

创建Serializer对象格式说明

Serializer的构造方法为:

serializer = BookInfoSerializer(instance=None, data=empty, **kwarg)

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

serializer = BookInfoSerializer(instance=None, data=empty, context={'request': request})
# 通过context参数附加的数据,可以通过Serializer对象的context属性获取。

序列化使用

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

python manage.py shell
1 基本使用

1) 先查询出一个图书对象

from bookapp.models import BookInfo

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

2) 构造序列化器对象

from bookapp.serializers import BookInfoSerializer

serializer = BookInfoSerializer(book)

3)获取序列化数据

# 通过data属性可以获取序列化后的数据,序列化器定义了几个字段就序列化几个字段
serializer.data
# { 'btitle': '天龙八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40}
# 实际开发中直接将序列化后的数据返回给前端开发人员使用

4)如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明

books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
serializer.data
# [OrderedDict([('btitle', '天龙八部'), ('bpub_date', '1986-07-24'), ('bread', 36), ('bcomment', 40)], OrderedDict([('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80)]), OrderedDict([('btitle', '雪山飞狐'), ('bpub_date', '1987-11-11'), ('bread', 58), ('bcomment', 24)]), OrderedDict([('btitle', '西游记'), ('bpub_date', '1988-01-01'), ('bread', 10), ('bcomment', 10)])]
2 关联对象嵌套序列化

对序列化器添加代码:

from rest_framework import serializers

class BookInfoSerializer1(serializers.Serializer):
    btitle = serializers.CharField()
    bpub_date = serializers.DateField()

class HeroInfoSerializer(serializers.Serializer):
    hname = serializers.CharField()
    hcomment = serializers.CharField()
    # 此字段将被序列化为关联对象的主键。
    hbook = serializers.PrimaryKeyRelatedField(read_only=True)
    #此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
    hbook = serializers.StringRelatedField(read_only=True)
    # 使用关联对象的序列化器
    hbook = BookInfoSerializer1()


class BookInfoSerializer(serializers.Serializer):
    btitle = serializers.CharField(min_length=3,max_length=20)
    bpub_date = serializers.DateField()
    bread = serializers.IntegerField(read_only=True)
    # 此字段将被序列化为关联对象的主键。
    heroinfo_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
    # 此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
    heroinfo_set = serializers.StringRelatedField(read_only=True,many=True)
    # 使用关联对象的序列化器
    heroinfo_set = HeroInfoSerializer(many=True)

以BookInfoSerializer序列化器的代码进行说明:
1) PrimaryKeyRelatedField:
指明字段时需要包含read_only=True或者queryset参数

# 此字段将被序列化为关联对象的主键。
heroinfo_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)

shell中使用效果:

from bookapp.serializers import BookInfoSerializer
from bookapp.models import BookInfo

book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
{'bread': 36, 'heroinfo_set': [6, 7, 8, 9], 'bpub_date': '1986-07-24', 'btitle': '天龙八部'}

2) StringRelatedField

    # 此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
    heroinfo_set = serializers.StringRelatedField(read_only=True,many=True)

shell中使用效果:

from bookapp.serializers import BookInfoSerializer
from bookapp.models import BookInfo

book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
{'heroinfo_set': ['乔峰', '段誉', '虚竹', '王语嫣'], 'btitle': '天龙八部', 'bread': 36, 'bpub_date': '1986-07-24'}

3)使用关联对象的序列化器

    # 使用关联对象的序列化器
    heroinfo_set = HeroInfoSerializer(many=True)

shell中使用效果:

from bookapp.serializers import BookInfoSerializer
from bookapp.models import BookInfo

book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
{'btitle': '天龙八部', 'bread': 36, 'bpub_date': '1986-07-24', 'heroinfo_set': [OrderedDict([('hname', '乔峰'), ('hcomment', '降龙十八掌')]), OrderedDict([('hname', '段誉'), ('hcomment', '六脉神剑')]), OrderedDict([('hname', '虚竹'), ('hcomment', '天山[('hname', '王语嫣'), ('hcomment', '神仙姐姐')])]}

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

反序列化使用

1 验证

使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
如我们前面定义过的BookInfoSerializer:

btitle = serializers.CharField(min_length=3,max_length=20)

在反序列化时会对btitle的值进行验证其长度是否大于3小于20
我们现在重写BookInfoSerializer序列化器:

from rest_framework import serializers
from book.models import BookInfo

class BookInfoSerializer(serializers.Serializer):
    btitle = serializers.CharField(min_length=3,max_length=20)
    bpub_date = serializers.DateField()
    bread = serializers.IntegerField(read_only=True)
    # 序列化附表的主建
    # heroinfo_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
    # 序列化附表的__str__方法的返回值
    # heroinfo_set = serializers.StringRelatedField(read_only=True,many=True)
    # 使用附表的序列化器
    # heroinfo_set = HeroInfoSerializer(many=True)

    # 定义单一字段验证的方法
    def validate_btitle(self, value):
        if value == 'python':
            raise serializers.ValidationError('书名不符合规范')
        return value

    # 定义多字段验证方法
    def validate(self, attrs):
        if attrs['btitle'] == 'itcast':
            raise serializers.ValidationError('itcast不符合规范')
        return attrs

    # 定义保存方法
    def create(self, validated_data):
        book = BookInfo.objects.create(btitle=validated_data['btitle'], bpub_date=validated_data['bpub_date'])
        return book

    # 定义更新方法
    def update(self, instance, validated_data):
        instance.btitle = validated_data['btitle']
        instance.bpub_date = validated_data['bpub_date']
        instance.save()
        return instance

我们在bookapp的views中书写使用的代码:

class BooksView(View):
    # 保存图书
    def post(self, request):
        data_dict = json.loads(request.body.decode())

        # 构造序列化对象,并将要反序列化的数据传递给data构造参数,进而进行验证
        serializer = BookInfoSerializer(data=data_dict)
        # 验证数据,数据错误时直接返回给前端错误提示
        serializer.is_valid(raise_exception=True)
        # 保存数据到数据库
        serializer.save()

        return http.JsonResponse(serializer.data)

class BookView(View):
    # 更新单一图书
    def put(self, request, pk):

        data_dict = json.loads(request.body.decode())
        book = BookInfo.objects.get(id = pk)
        # 创建序列化对象,并将要反序列化的数据传递给data构造参数,进而进行验证
        serializer = BookInfoSerializer(book,data=data_dict)

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

        # 3、更新数据,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了
        # 如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。
        serializer.save()
        return http.JsonResponse(serializer.data)

注意:代码中的注释有对方法的详细说明

附录

模型类数据导入sql:

insert into tb_books(btitle,bpub_date,bread,bcomment,is_delete) values
('射雕英雄传','1980-5-1',12,34,0),
('天龙八部','1986-7-24',36,40,0),
('笑傲江湖','1995-12-24',20,80,0),
('雪山飞狐','1987-11-11',58,24,0);


insert into tb_heros(hname,hgender,hbook_id,hcomment,is_delete) values
('郭靖',1,1,'降龙十八掌',0),
('黄蓉',0,1,'打狗棍法',0),
('黄药师',1,1,'弹指神通',0),
('欧阳锋',1,1,'蛤蟆功',0),
('梅超风',0,1,'九阴白骨爪',0),
('乔峰',1,2,'降龙十八掌',0),
('段誉',1,2,'六脉神剑',0),
('虚竹',1,2,'天山六阳掌',0),
('王语嫣',0,2,'神仙姐姐',0),
('令狐冲',1,3,'独孤九剑',0),
('任盈盈',0,3,'弹琴',0),
('岳不群',1,3,'华山剑法',0),
('东方不败',0,3,'葵花宝典',0),
('胡斐',1,4,'胡家刀法',0),
('苗若兰',0,4,'黄衣',0),
('程灵素',0,4,'医术',0),
('袁紫衣',0,4,'六合拳',0);

你可能感兴趣的:(django-Serializer序列化器的简单使用)