DRF中的序列化器详细应用

 

视图的功能:说白了就是接收前端请求,进行数据处理

(这里的处理包括:如果前端是GET请求,则构造查询集,将结果返回,这个过程为序列化;如果前端是POST请求,假如要对数据库进行改动,则需要拿到前端发来的数据,进行校验,将数据写入数据库,这个过程称为反序列化)

最原始的视图可以实现这样的逻辑处理,但是针对不同的请求,需要在类视图中定义多个方法实现各自的处理,这样是可以解决问题,但是存在一个缺陷,那就是每个函数中一般的逻辑都差不多:读请求,从数据库拿数据,写东西到数据库,返回结果给前端。这样就会产生大量的重复代码。

在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:

增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回

删:判断要删除的数据是否存在 -> 执行数据库删除

改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回

查:查询数据库 -> 将数据序列化并返回

1. 安装DRF

  1. pip install djangorestframework

2. 添加rest_framework应用

我们利用在Django框架学习中创建的demo工程,在settings.py的INSTALLED_APPS中添加'rest_framework'。

  1. INSTALLED_APPS = [
  2. ...
  3. 'rest_framework',
  4. ]

为了节省我们写代码的时间,DRF框架为我们提供了实现视图的快捷方式。那么DRF框架的核心是什么?那就是序列化器实现序列化,反序列化以及视图

1.序列化器

定义序列化器(本质就是一个类),一般包括模型类的字段,有自己的字段类型规则。实现了序列化器后,就可以创建序列化对象以及查询集进行序列化操作,通过序列化对象.data来获取数据(不用自己构造字典,再返回Json数据)

1.用于序列化时,将模型类对象传入instance参数

2.用于反序列化时,将要被反序列化的数据传入data参数

3.除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

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

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

一个序列化器的例子:

  1. class BookInfoSerializer(serializers.Serializer):
  2. """图书序列化器"""
  3. id = serializers.IntegerField(label='ID', read_only=True)
  4. btitle = serializers.CharField(label='名称', max_length=)
  5. bpub_date = serializers.DateField(label='发布日期', required=False)
  6. bread = serializers.IntegerField(label='阅读量', required=False)
  7. bcomment = serializers.IntegerField(label='评论量', required=False)
  8. image = serializers.ImageField(label='图片', required=False)
  9.  
  10. # 在一方关联多方:在序列化书籍信息时,同时序列化出书籍关联的任务信息
  11. # StringRelatedField : 也是适用的,显示汉字字段而不是指定的PrimaryKey,这样更直观
  12. # many=True :指定heroinfo_set是多的那一方
  13. # read_only:该字段只能进行序列化,反序列化时直接忽略该字段
  14. heroinfo_set = serializers.PrimaryKeyRelatedField(label='英雄', read_only=True, many=True)

这样就可以通过:

  1. book = BookInfo.objects.get(id=) # 获取查询集
  2. s = BookInfoSerializer(book) # 将查询集绑定给序列化器
  3. print(s.data) # 通过序列化对象.data将数据读出来

一个反序列化例子:

  1. # 实现新增数据
  2. data = {'btitle':'钢铁是怎样炼成的'}
  3. s = BookInfoSerializer(data = data) # 将查询集绑定给序列化器
  4. serializer.is_valid(raise_exception=True) # 进行校验
  5. print(s.validated_data) # 通过序列化对象.data将数据读出来
  6.  
  7. # 实现修改数据
  8. data = {'btitle':'钢铁是怎样炼成的'}
  9. book = BookInfo.objects.get(id=) # 获取查询集
  10. s = BookInfoSerializer(book, data = data) # 将查询集以及前端传过来的数据绑定给序列化器
  11. serializer.is_valid(raise_exception=True) # 进行校验
  12. print(s.validated_data) # 通过序列化对象.data将数据读出来

raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。

从上边我们可以看到,反序列化要求我们进行数据的验证,默认会帮我们验证前端传来的数据是否合法。这里传入的是bititle,因为这个字段是必须传入的。is_valid()方法只能提供基础的验证,如果不能满足我们,就可以自定义新的验证。

自定义验证的方式:

1.给单个以及多个数据进行验证添加

  1. # 给某字段增加校验逻辑
  2. def validate_btitle(self, value): # 这里的value就是前端传来的数据,这里代表'钢铁是怎样炼成的'
  3. if 'fenghua' not in value.lower():
  4. raise serializers.ValidationError('bititle必须包含fenghua字段')
  5. return value
  6.  
  7. # 给多个字段增加校验
  8. def validate(self, attrs):
  9. bread = attrs['bread']
  10. bcomment = attrs['bcomment']
  11. if bread < bcomment:
  12. raise serializers.ValidationError('阅读量小于评论量')
  13. return attrs

2.给所有字段都增加验证(在序列化器外边进行函数定义,在序列化器内部字段中添加validators属性即可)

  1. def about_django(value):
  2. if 'django' not in value.lower():
  3. raise serializers.ValidationError("图书不是关于Django的")
  4.  
  5. class BookInfoSerializer(serializers.Serializer):
  6. """图书数据序列化器"""
  7. id = serializers.IntegerField(label='ID', read_only=True)
  8. # 在字段中添加validators,进行外边函数的添加
  9. btitle = serializers.CharField(label='名称', max_length=, validators=[about_django])
  10. bpub_date = serializers.DateField(label='发布日期', required=False)
  11. bread = serializers.IntegerField(label='阅读量', required=False)
  12. bcomment = serializers.IntegerField(label='评论量', required=False)
  13. image = serializers.ImageField(label='图片', required=False)

那么验证之后就可以了吗?不是,还需要将验证后的数据进行保存!!

实现:在序列化器中定义两个方法进行数据写入:

复习:数据库增加数据

  1. # 方式1
  2. book = BookInfo(
  3. btitle='西游记',
  4. bput_date=date(,,),
  5. bread=,
  6. bcomment=
  7. )
  8. book.save()
  9.  
  10. 方式2
  11. book.create(
  12. btitle='西游记',
  13. bput_date=date(,,),
  14. bread=,
  15. bcomment=
  16. )
  1. # 校验后保存数据,实现父类声明的方法
  2. # validated_data是经过校验之后的数据,已经是标准的字典
  3. def create(self, validated_data):
  4. # 对字典进行拆包
  5. return BookInfo.objects.create(**validated_data)
  6.  
  7. def update(self, instance, validated_data):# instance是数据集对象
  8. # 取不到就取默认值
  9. instance.btitle = validated_data.get('btitle', instance.btitle)
  10. instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
  11. instance.bread = validated_data.get('bread', instance.bread)
  12. instance.bcomment = validated_data.get('bcomment', instance.bcomment)
  13. instance.save()
  14. return instance

两点说明:

1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到

  1. serializer.save(owner=request.user)

2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新

  1. # Update `comment` with partial data
  2. serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

2.模型类序列化器

上边我们自定义序列化器需要将好多字段在序列化器中定义,比较复杂。模型类序列化器提供了更快捷的方式帮我们更快的提供了序列化器。

ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()和update()的实现

1. 定义

比如我们创建一个BookInfoSerializer

  1. class BookInfoSerializer(serializers.ModelSerializer):
  2. """图书数据序列化器"""
  3. class Meta:
  4. model = BookInfo
  5. fields = '__all__'
  • model 指明参照哪个模型类
  • fields 指明为模型类的哪些字段生成

我们可以在python manage.py shell中查看自动生成的BookInfoSerializer的具体实现

  1. from booktest.serializers import BookInfoSerializer
  2. serializer = BookInfoSerializer()
  3. serializer
  4. BookInfoSerializer():
  5. id = IntegerField(label='ID', read_only=True)
  6. btitle = CharField(label='名称', max_length=)
  7. bpub_date = DateField(allow_null=True, label='发布日期', required=False)
  8. bread = IntegerField(label='阅读量', max_value=, min_value=-, required=False)
  9. bcomment = IntegerField(label='评论量', max_value=, min_value=-, required=False)
  10. image = ImageField(allow_null=True, label='图片', max_length=, required=False)

2.指定字段

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

  1. class BookInfoSerializer(serializers.ModelSerializer):
  2. """图书数据序列化器"""
  3. class Meta:
  4. model = BookInfo
  5. fields = ('id', 'btitle', 'bpub_date')

2.使用exclude可以明确排除掉哪些字段

  1. class BookInfoSerializer(serializers.ModelSerializer):
  2. """图书数据序列化器"""
  3. class Meta:
  4. model = BookInfo
  5. exclude = ('image',)

3. 默认ModelSerializer使用主键作为关联字段,但是我们可以使用depth来简单的生成嵌套表示,depth应该是整数,表明嵌套的层级数量。如:

  1. class HeroInfoSerializer2(serializers.ModelSerializer):
  2. class Meta:
  3. model = HeroInfo
  4. fields = '__all__'
  5. depth =

形成的序列化器如下:

  1. HeroInfoSerializer():
  2. id = IntegerField(label='ID', read_only=True)
  3. hname = CharField(label='名称', max_length=)
  4. hgender = ChoiceField(choices=((, 'male'), (, 'female')), label='性别', required=False, validators=[<django.core.valators.MinValueValidator object>, <django.core.validators.MaxValueValidator object>])
  5. hcomment = CharField(allow_null=True, label='描述信息', max_length=, required=False)
  6. hbook = NestedSerializer(read_only=True):
  7. id = IntegerField(label='ID', read_only=True)
  8. btitle = CharField(label='名称', max_length=)
  9. bpub_date = DateField(allow_null=True, label='发布日期', required=False)
  10. bread = IntegerField(label='阅读量', max_value=, min_value=-, required=False)
  11. bcomment = IntegerField(label='评论量', max_value=, min_value=-, required=False)
  12. image = ImageField(allow_null=True, label='图片', max_length=, required=False)

4. 显示指明字段,如:

  1. class HeroInfoSerializer(serializers.ModelSerializer):
  2. hbook = BookInfoSerializer()
  3.  
  4. class Meta:
  5. model = HeroInfo
  6. fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')

5.指明只读字段

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

  1. class BookInfoSerializer(serializers.ModelSerializer):
  2. """图书数据序列化器"""
  3. class Meta:
  4. model = BookInfo
  5. fields = ('id', 'btitle', 'bpub_date' 'bread', 'bcomment')
  6. read_only_fields = ('id', 'bread', 'bcomment')

3.添加额外参数

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

  1. class BookInfoSerializer(serializers.ModelSerializer):
  2. """图书数据序列化器"""
  3. class Meta:
  4. model = BookInfo
  5. fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
  6. extra_kwargs = {
  7. 'bread': {'min_value': , 'required': True},
  8. 'bcomment': {'min_value': , 'required': True},
  9. }
  10.  
  11. # BookInfoSerializer():
  12. # id = IntegerField(label='ID', read_only=True)
  13. # btitle = CharField(label='名称', max_length=)
  14. # bpub_date = DateField(allow_null=True, label='发布日期', required=False)
  15. # bread = IntegerField(label='阅读量', max_value=, min_value=, required=True)
  16. # bcomment = IntegerField(label='评论量', max_value=, min_value=, required=True)

DRF中的序列化器的更多相关文章

  1. 经历了源码的痛苦,掌握DRF的核心序列化器

    目录 DRF的核心--序列化器 序列化器 什么是序列化和反序列化? 序列化 序列化demo 字段类型 字段参数 序列化自定制返回字段 方法一:在序列化类(serializers.py)中写 方法二:在 ...

  2. DRF项目之序列化器和视图重写方法的区别

    我们,都知道,DRF框架是一款高度封装的框架. 我们可以通过重写一些方法来实现自定义的功能. 今天,就来说说在视图中重写和序列化器中重写方法的区别. 在视图中重写方法: 接收请求,处理数据(业务逻辑) ...

  3. DRF框架之序列化器初体验

    首先,我们需要明白序列化和反序列化的过程指的是什么. 序列化操作:将模型数据 ---> 字典数据 --->JSON数据(响应JSON数据的操作) 反序列化操作:将JSON数据 ---> ...

  4. day71:drf:API接口&Restful API规范&Django Rest Framework&drf中的序列化和反序列化功能

    目录 1.web应用模式 2.API接口 3.Restful API规范 4.序列化 5.Django Rest Framework 1.drf的简单介绍 2.drf的特点 3.如何安装drf 4.d ...

  5. Django REST framework 中的序列化器

    在此之前定义一个序列化工具:     views中的的代码 from rest_framework.viewsets import ModelViewSet from .models import B ...

  6. Hive中自定义序列化器(带编码)

    hive SerDe的简介 https://www.jianshu.com/p/afee9acba686 问题 数据文件为文本文件,每一行为固定格式,每一列的长度都是定长或是有限制范围,考虑采用hiv ...

  7. 一: DRF web应用框架基础,及序列化器的使用

    ---恢复内容开始--- 一: web 应用模式(有两种) 1: 前后端不分离(前端从后端直接获取数据) 2: 前后端分离 二: api 接口 原因一: 为了在团队内部形成共识.防止个人习惯差异引起的 ...

  8. drf之序列化器的使用

    一.序列化器-Serializer 作用: 1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串 2. 完成数据校验功能 3. 反序列化,把客户端发送过来的数据,经 ...

  9. DRF序列化器

    序列化器-Serializer 作用: 1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串 2. 反序列化,把客户端发送过来的数据,经过request以后变成字典 ...

随机推荐

  1. LeetCode - Maximum Frequency Stack

    Implement FreqStack, a class which simulates the operation of a stack-like data structure. FreqStack ...

  2. zombodb 得分以及高光

    得分以及高光在搜索引擎中有很重要的作用 得分zdb.score 使用方法 zdb.score(tid) 参考示例 SELECT zdb.score(ctid), * FROM products WHE ...

  3. cmake编译obs

    https://blog.csdn.net/su_vast/article/details/74984213 https://blog.csdn.net/u011258240/article/deta ...

  4. 使用 vue-cli-service inspect 来查看一个 Vue CLI 3 项目的 webpack 配置信息(包括:development、production)

    使用 vue-cli-service inspect 来查看一个 Vue CLI 3 项目的 webpack 配置信息(包括:development.production) --mode 指定环境模式 ...

  5. django 获取用户提交的数据 文件 表单

    templates: <div> <form action="/detail" method="post" enctype="mul ...

  6. selenium基础用法(爬虫)

    初识selenium selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏 ...

  7. 模拟器运行android镜像

    编译完成后需要运行一下,看看效果,操作中出现很多问题   先说明android4.0的,然后说明一下android2.3.4的,两者是一样的   一.android4.0.1 可以参看如下链接: ht ...

  8. centos7如何查看网络状态?

    参考https://www.jb51.net/os/RedHat/520187.html 查看网络状态: lsof -Pnl +M -i4 显示ipv4服务及监听端情况 netstat -anp 所有 ...

  9. 在WINDOWS7下无U盘安装WINDOWS10

    第一步:下载cn_windows_10_business_editions_version_1803_updated_march_2018_x64_dvd_12063730.iso 第二步:解压里面的 ...

  10. Java构造器练习题

    仔细阅读下面的程序 public class Car { String name = "汽车"; public Car(String name) { this.name = nam ...