[Django REST framework - 序列化组件、source、钩子函数]


序列化器-Serializer

什么是rest_framework序列化?

在写前后端不分离的项目时:
 我们有form组件帮我们去做数据校验
 我们有模板语法,从数据库取出的queryset对象不需要人为去转格式
当我们写前后端分离项目的时:
 我们需要自己去做数据校验
 我们需要手动去转数据格式,因为跨平台数据传输都用json字符串,不能直接jsonqueryset对象

序列化器的作用

1 序列化:把python中的对象转成json格式字符串
序列化器会把模型对象转换成字典,经过response以后变成json字符串 2 反序列化:把json格式字符串转成python中的对象
把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型

3 注意:drf的序列化组件(序列化器)
把对象(Book,queryset对象)转成字典
因为有字典,直接丢到Response中就可以了
序列化,反序列化
-对象----》json
-json---》对象 序列化器
-定义一个类,继承Serializer
-在类内些字段(常用字段,和非常用字段)(字段参数)
-在视图类中,实例化得到一个序列化类的对象,传入要序列化的数据
-对象.data---》就是字典
-source

序列化器的基本使用

from rest_framework.serializers import Serializer,ModelSerializer
from rest_framework import serializers
Serializer是rest_framework原生的序列化组件
ModelSerializer是rest_framework在原生的序列化组件的基础上封装了一层的序列化组件
用法:1、在用我们的rest_framework序列化组件的时候,我们的视图层都必须写视图类,不能再写视图函数    2、我们需要针对每一张模型表写一个类来继承Serailizer或者ModelSerailizer类,  注:当我们在视图类里需要对数据进行序列化或者反序列化的时候,在自己定义的类传入需要序列化的数据实例化,
   调用.data即可拿到序列化或者校验后的数据了

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

1 写一个序列化的类,继承Serializer
class BookSerializer(serializers.Serializer):
# 在这里写要序列化的字段
# 序列化字段类(有很多,常用的就几个,等同于models中的字段类)
# 字段类,有很多字段参数()
name = serializers.CharField()
price = serializers.IntegerField()
# publish = serializers.CharField()
2 在类中写要序列化的字段(常用字段,和非常用字段)(字段参数)
name = serializers.CharField()
price = serializers.IntegerField()
3 在视图类中使用(实例化得到一个序列化类的对象,传入要序列化的数据)
class BookView(APIView):
def get(self, request):
book_list = models.Book.objects.all()
# instance=None, 要序列化的数据
# data=empty ,要反序列化的数据(目前data先不用)
# many=True 如果序列化多条,一定要写many=True
book_ser = BookSerializer(instance=book_list, many=True)
# book_ser.data就是序列化后的数据
return Response(book_ser.data)
4 得到序列化后的数据,返回(对象.data---》就是字典)
book_ser.data 5 字段参数,source,指定要序列化表中的哪个字段 ##########具体操作步骤见下方详细操作#########

路由层 urls.py

from django.urls import path
from app import views urlpatterns = [
path('admin/', admin.site.urls),
# 获取所有的书籍信息
path('books_new/', views.BookView.as_view()),
# 对某本书进行操作
path('books_new/<int:id>/', views.BookViewId.as_view()), ]

模型层 models.py

from django.db import models

class Book(models.Model):
name = models.CharField(max_length=32, verbose_name='书名')
publish = models.CharField(max_length=32, verbose_name='出版社')
price = models.IntegerField(verbose_name='价格')

序列化器层 serializer.py

from rest_framework import serializers
from app import models # 新建序列化类,继承Serializer
class BookSerializer(serializers.Serializer):
# 类中定义和模型表一一对应的字段,在这里写要序列化的字段
# 序列化字段类(有很多,常用的就几个,等同于models中的字段类)
# 字段类,有很多字段参数()
name = serializers.CharField()
price = serializers.IntegerField()
publish = serializers.CharField()

视图层 views.py

# 获取所有书籍信息
class BookView(APIView):
def get(self, request):
book_list = models.Book.objects.all()
book_ser = BookSerializer(instance=book_list, many=True)
# book_ser.data就是序列化后的数据
return Response(book_ser.data) """
instance=None, 要序列化的数据
data=empty ,要反序列化的数据(目前data先不用)
many=True 如果序列化多条,一定要写many=True
"""
# 对某一本书进行操作
class BookViewId(APIView):
# 对某一个进行操作需要带上id
def get(self, request, id):
book = models.Book.objects.all().filter(pk=id).first()
book_ser = BookSerializer(instance=book)
return Response(book_ser.data)

source

1 指定要序列化的字段(数据表中字段)
  publish = serializers.CharField(source='publish.city') # 拿到出版社所在的城市

2 用的最多:只有一个字段(也可以跨表)

SerializerMethodField

用的最多:跨表查((来定制返回的字段)要么是列表,要么是字典)
publish=serializers.SerializerMethodField()
def get_publish(self,obj):
print(obj)
# return {'name':'sss','city':'sss'}
return {'name':obj.publish.name,'city':obj.publish.city,'email': obj.publish.email}

在模型表中写方法

# models.py 表模型中写的
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateField() publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
authors=models.ManyToManyField(to='Author')
def __str__(self):
return self.name # def publish_name(self):
# return self.publish.name def publish_name(self):
return {'name':self.publish.name,'city':self.publish.city}

@property
def author_list(self): # 列表推导式
return [{'name':author.name,'age':author.age,'id':author.nid} for author in self.authors.all()]

# serializers.py 序列化类中
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.IntegerField()

publish_name = serializers.DictField()
author_list = serializers.ListField()

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

序列化类常用字段类型及属性

字段参数针对性分类

# 针对charfield
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
# 针对interfield
max_value 最小值
min_value 最大值 # 通用的,大家都有
# 这两个最重要
read_only 表明该字段仅用于序列化输出,默认False(序列化)
write_only 表明该字段仅用于反序列化输入,默认False(反序列化) required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
error_messages 包含错误编号与错误信息的字典 validators 该字段使用的验证器(了解)

反序列化,局部钩子,全局钩子

使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

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

验证成功,可以通过序列化器对象的validated_data属性获取数据。

在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。

1 如果要反序列化,继承了Serializer,必须重写create方法

2 使用
# 视图类
def post(self, request):
publish_ser = serializer.PublishSerializer(data=request.data)
if publish_ser.is_valid(): # 校验数据
# 直接保存,保存到哪个表里?需要重写save
publish_ser.save()
return Response(publish_ser.data)
else:
print(publish_ser.errors)
return Response('数据有问题啊') # 序列化类
def create(self, validated_data):
# 校验过后的数据
res = models.Publish.objects.create(**validated_data)
return res
"""
父类的save内部调用了create,所以我们重写create
return res 给了self.instance以后,instance就有值了
publish_ser.data,instance就有值调用data就能拿到序列化后的数据 is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,
REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
"""

局部和全局钩子

# validate_字段名
def validate_name(self, data):
# data就是当前字段的值
if data.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
return data # 在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证
def validate(self, attrs):
if attrs.get('name') == attrs.get('city'):
raise ValidationError('city和名字不能一样')
else:
return attrs

模型类序列化器

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类
ModelSerializer与常规的Serializer相同,但提供了:
  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()和update()的实现

视图类 views.py

class BookView(APIView):
def get(self,request):
qs=models.Book.objects.all()
ser=serializer.BookModelSerializer(instance=qs,many=True)
return Response(ser.data) def post(self,request):
ser = serializer.BookModelSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors) class BookDetailView(APIView):
def get(self,request,id):
book = models.Book.objects.filter(pk=id).first()
ser = serializer.BookModelSerializer(instance=book)
return Response(ser.data)
def put(self,request,id):
book = models.Book.objects.filter(pk=id).first()
ser = serializer.BookModelSerializer(instance=book,data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors) def delete(self,request,id):
res = models.Book.objects.filter(pk=id).delete()
if res[0] > 0:
return Response('')
else:
return Response('要删的不存在')

序列化类 serializers.py

"""
ModelSerializer
使用步骤:
1、新建序列化类,继承ModelSerializer
2、类中定义和模型表一一对应的字段,这里可以定义class Meta() 然后指定模型表model和 映射字段fields,比Serializer更简洁
-其中类中的名字可以改变,需要在serializers.CharField()的括号中指定source=某个字段,建议映射关系
-外键关系的字段可以用serializers.SerializerMethodField(),需要在下方固定写 get_字段名 的方法,
这里可以写具体逻辑,最终返回结果就是该字段的结果
3、当新增数据的时候不需要重写父类的create方法,这里ModelSerializer做了封装
4、当修改数据的时候不需要重写父类的update方法,这里ModelSerializer做了封装
5、当完成这些配置后就可以在视图类中实例化调用了,序列化的时候序列化,反序列化的时候校验 """ from rest_framework import serializers
from app import models class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book # model 指明参照哪个模型类
fields = '__all__' # fields 指明为模型类的哪些字段生成,__all__表名包含所有字段 # 给字段类加属性
extra_kwargs = {
'publish': {'required': True, 'write_only': True},
'authors': {'required': True, 'write_only': True},
}
publish_detail = PublishSerializer(source='publish',read_only=True)
author_list=serializers.ListField(read_only=True)
# 字段自己的校验,全局钩子,局部钩子 """
使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
使用exclude可以明确排除掉哪些字段
使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
"""

表模型 models.py

这是完整的模型表,上面的视图和序列化类只展示了部分表的增删改查演示
from django.db import models

class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32, verbose_name='书名')
price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='价格')
publish_date = models.DateField(verbose_name='出版时间') publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
authors=models.ManyToManyField(to='Author')
class Meta:
verbose_name_plural = '书籍表' def __str__(self):
return self.name # 表模型写方法,展示更多字段
# def publish_name(self):
# return self.publish.name # def publish_name(self):
# return {'name':self.publish.name,'city':self.publish.city}
#
# @property
# def author_list(self):
# return [{'name':author.name,'age':author.age,'id':author.nid} for author in self.authors.all()] class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32, verbose_name='名字')
age = models.IntegerField(verbose_name='年龄')
author_detail = models.OneToOneField(to='AuthorDetail',to_field='nid',unique=True,on_delete=models.CASCADE)class Meta:
verbose_name_plural = '作者表' def __str__(self):
return self.name class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
telephone = models.BigIntegerField(verbose_name='电话')
birthday = models.DateField(verbose_name='生日')
addr = models.CharField(max_length=64, verbose_name='地址')
class Meta:
verbose_name_plural = '作者详情表' class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32, verbose_name='社名')
city = models.CharField(max_length=32, verbose_name='地址')
email = models.EmailField(verbose_name='邮箱')
class Meta:
verbose_name_plural = '出版社表' def __str__(self):
return self.name

路由urls.py

urlpatterns = [
  path('books/',views.BookView.as_view()),
  path('books/<int:id>/',views.BookDetailView.as_view()),
]

序列化高级用法

ModelSerializer用的基本就是下面这个方法
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__" """
如果想让字段更丰富些,可以采用任意一种方法实现(方法有很多种)
第一种方法:source
publish = serializers.CharField(source='publish.city') 第二种方法:SerializerMethodField
publish=serializers.SerializerMethodField()
def get_publish(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city,'email': obj.publish.email} 第三种方法:在表模型写方法
def publish_name(self):
return {'name':self.publish.name,'city':self.publish.city} @property
def author_list(self):
return [{'name':author.name,'age':author.age,'id':author.nid} for author in self.authors.all()] 第四种方法:子序列化
publish = Publishserializer()
"""

[Django REST framework - 序列化组件、source、钩子函数]的更多相关文章

  1. django rest framework 序列化组件总结

    序列化组件总结 一. 序列化组件本质上为了实现前后端分离,而进行json序列化的一个组件形式,极大方便了解析数据的作用 二. 所有序列化是基于APIView 解析器实现的,通过内部的多继承关系方便实现 ...

  2. Django REST Framework序列化器

    Django序列化和json模块的序列化 从数据库中取出数据后,虽然不能直接将queryset和model对象以及datetime类型序列化,但都可以将其转化成可以序列化的类型,再序列化. 功能需求都 ...

  3. [Django REST framework - 视图组件之视图基类、视图扩展类、视图子类、视图集]

    [Django REST framework - 视图组件之视图基类.视图扩展类.视图子类.视图集] 视图继承关系 详图见文章末尾 视图组件可点我查看 两个视图基类:APIView.GenericAP ...

  4. Django框架 之 form组件的钩子

    Django框架 之 form组件的钩子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 3 ...

  5. Django forms组件与钩子函数

    目录 一.多对多的三种创建方式 1. 全自动 2. 纯手撸(了解) 3. 半自动(强烈推荐) 二.forms组件 1. 如何使用forms组件 2. 使用forms组件校验数据 3. 使用forms组 ...

  6. ajax提交文件,django测试脚本环境书写,froms组件,钩子函数

    1.在新版本中,添加app是直接在settings设置中,将INSTALLED_APPS里添加app名字, 但是他的完整写法是   'app01.apps.App01Config'  因为新版本做了优 ...

  7. django之表多对多建立方式、form组件、钩子函数 08

    目录 多对多三种创建方式 1.全自动(用ManyToManyField创建第三张表) 2.纯手写 3.半自动 form组件 引入 form组件的使用 forms组件渲染标签 form表单展示信息 fo ...

  8. Django REST framework序列化

    一.简介 Django REST framework是基于Django实现的一个RESTful风格API框架,能够帮助我们快速开发RESTful风格的API. 官网:https://www.djang ...

  9. Django REST Framework 序列化和校验 知识点

    DRF序列化 Django ORM对象 --> JSON格式的数据 序列化 JSON格式的数据 --> Django ORM数据 反序列化 需要两个工具: from rest_framew ...

随机推荐

  1. Mac 搭建 Sentry

    Sentry 为我们提供应用程序的错误跟踪,使我们能够快速定位到错误所在的文件和行号. 以下是官网支持语言和框架的部分截图: 准备工作 自 2020 年 12 月 4 日起,Sentry 默认使用 P ...

  2. 论文翻译:Conv-TasNet: Surpassing Ideal Time–Frequency Magnitude Masking for Speech Separation

    我醉了呀,当我花一天翻译完后,发现已经网上已经有现成的了,而且翻译的比我好,哎,造孽呀,但是他写的是论文笔记,而我是纯翻译,能给读者更多的思想和理解空间,并且还有参考文献,也不错哈,反正翻译是写给自己 ...

  3. CSS3 变形

    目录 Transform Transform与坐标系统 transform-origin transform-style 二维旋转 旋转 rotate 平移 translate translateX ...

  4. [Python] 基本概念

    1.基本概念 三大特性:封装.继承.多态 继承:派生类继承基类的字段和方法 多态:对不同类型的变量进行相同的操作,却表现出不同的行为(例如对数字和字符做"+"运算) 封装:将数据和 ...

  5. [bug] Maven [WARNING] 'parent.relativePath' of POM

    参考 https://blog.csdn.net/simajinxiu/article/details/86667894

  6. 云计算OpenStack---虚拟机获取不到ip(12)

    一.现象描述 openstack平台中创建虚拟机后,虚拟机在web页面中显示获取到了ip,但是打开虚拟机控制台后查看网络状态,虚拟机没有ip地址,下图为故障截图: 二.分析 1.查看neutron服务 ...

  7. Java 关键字详解

    Java 关键字是 Java 语言中被赋予特殊意义的一些单词(每个关键字都代表着不同场景下的不同含义),不可以把它当作标识符来使用(不能用作变量名.方法名.类名.包名和参数名等).Java 中的关键字 ...

  8. python文件处理(对比和筛选)版本2

    场景:对比两个txt文件的差异,将对比结果写入html,将不同部分写入另一个txt #!/user/bin/python #!coding=utf-8 # -*- coding: utf-8 -*- ...

  9. HTML的一些标签以及表单

    HTML的一些标签以及表单 图片标签 属性 说明 src 图像的路径 alt 图像不能显示时的替换文字 title 鼠标悬停时显示的内容 border 设置图像边框的宽度 align 对齐方式 相对路 ...

  10. Crontab 的使用方法

    第1列分钟1-59第2列小时1-23(0表示子夜)第3列日1-31第4列月1-12第5列星期0-6(0表示星期天)第6列要运行的命令 下面是crontab的格式:分 时 日 月 星期 要运行的命令 这 ...