当前位置:网站首页>drf序列化器-Serializer
drf序列化器-Serializer
2022-08-02 14:01:00 【意大利面拌42号混凝土】
Python之drf序列化器-Serializer
一、序列化器-Serializer的作用
- 序列化,序列化器会将模型类对象转化为字典,经过Response变成json字符串
- 反序列化,把客户发送过来的数据,经过request以后变成字典,序列化器可以将字典转成模型
- 反序列化,校验客户发送数据的合法性
二、定义序列化器
- Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
需要先在数据库中建立一个模型类(建表)
from django.db import models
# Create your models here.
class Student(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
在应用下新建serializer.py文件(名字可以随意取,一般使用serializer),在文件中导入刚才建立的表并导入serializers。如下
from rest_framework import serializers
from .models import Student
# 定义序列化器
class StudentSerializer(serializers.Serializer):
# 在下面写入想要序列化的字段名称
name = serializers.CharField()
age = serializers.IntegterField()
上述一写一个序列化类就已经完成了,下一步在view.py视图函数中填入相应的代码即可。如下
from django.shortcuts import render
# Create your views here.
import models
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import StudentSerializes
class Student(APIView);
def get(self,request):
back_dic = {
'code':200,'msg':'成功','result':''}
queryset_obj = models.Student.objects.all()
res = StudentSerializers(instance=query_obj,many=True)
if not res.is_valid():
back_dic['code'] = 1001
back_dic['msg'] = '失败'
return Response(back_dic)
back_dic['result'] = res.data
return Response(back_dic)
此时使用postman调用接口时便可以获取到数据库内所存储的数据并数据是以json格式发送到前端
这个数据从字典或者Queryset对象转为json的操作,便是序列化类StudentSerializes做的
# Serializer的构造方法为:
Serializer(instance=None, data=empty, **kwarg)
""" 1)用于序列化时,将模型类对象传入instance参数 2)用于反序列化时,将要被反序列化的数据传入data参数 3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据 """
serializer = AccountSerializer(account, context={
'request': request})
""" 1、使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。 2、序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。 3、序列化器的字段声明类似于我们前面使用过的表单系统。 4、开发restful api时,序列化器会帮我们把模型数据转换成字典. 5、drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典. """
**注意: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页面时,显示的字段帮助提示信息·1· |
四、序列化器高级用法
1、source用法
from rest_framework import serializers
from .models import Student
# 定义序列化器
class StudentSerializer(serializers.Serializer):
# 在下面写入想要序列化的字段名称
name = serializers.CharField()
age = serializers.IntegterField()
在上面的序列化name字段中,如果你不想让前端看到你表中实际的字段可以使用source方法,
soucre方法是当前名称映射到本表中的某个字段,这样当前名称在前端就能获取到表中映射字段的值,如下
name1 = serializers.CharField(source='name',read_only=True )
name = serializers.ChsrField(write_only=True)
常配合read_only与write_only使用
2、serializers.SerializerMethodField用法
SerializerMethodField可以规定序列化的字段的显示样式
- 在django2.0以上,模型类的字段以外键关联时都需要加on_delete=models.CASCADE(级联删除)
# 新模型表
from django.db import models
# Create your models here.
class Student(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
publish = models.ForeignKey(to='publish',on_delete=models.CASCADE)
class Publish(model.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=256)
以外键关联的字段在前端(postman)中显示的是对象
SerializerMethodField方法可以用来显示外键关联的详情数据
# 此时在serializer.py中就需要用到SerializerMethodField方法了
from rest_framework import serializers
from .models import Student
# 定义序列化器
class StudentSerializer(serializers.Serializer):
# 在下面写入想要序列化的字段名称
name = serializers.CharField()
age = serializers.IntegterField()
# 方法一(在序列化类中写)
pulish = serializers.SerializerMethodField() # 缺点 只能用来序列化 默认就是read_only=True
def get_publish(self,obj): # get_字段名
# return obj.publish.name # 显示出版社名字
return {
'id':obj.publish.id,'name':obj.publish.name,'addr':obj.publish.addr} # 返回出版社详情
# 方式二(在模型类中写,方法返回什么,下面的字段就是什么) 用的多
pulish_detail = serializers.CharField() # 这种返回到前端就是字典的形式,不是json格式的
pulish_detail = serializers.DictField() # 使用DictField返回的就是json格式
# 在模型类中写一个属性
@property
def pulish_detail(self):
return {
'id':self.publish.id,'name':self.publish.name,'addr':self.publish.addr}
# 方式三(了解)
pulish_detail = serializers.CharField(source='publish.name')
五、反序列化
一、数据验证
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用**is_valid()**方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
1、自定义验证
validate_字段名(也叫局部钩子)
# validate_字段名 对单个字段加验证
# 在序列化类里进行验证
def validate_name(self,value)
if '草' in value:
raise ValidationError('不符合社会主义核心价值观')
return value
validate(也叫全局钩子)
# validate同时对多个字段进行比较验证时,可以定义validate方法来验证
def validate(self, attrs):
bread = attrs['bread']
bcomment = attrs['bcomment']
if bread < bcomment:
raise serializers.ValidationError('阅读量小于评论量')
return attrs
validators
# 在字段中添加validators选项参数,也可以补充验证行为,如
btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django])
二、保存数据
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.
可以通过重写create()和update()两个方法来实现
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
...
def create(self, validated_data):
"""新建"""
res = BookInfo.objects.create(**validated_data)
return res
def update(self, instance, validated_data):
"""更新,instance为要更新的对象实例"""
instance.btitle = validated_data.get('btitle', instance.btitle)
instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
instance.bread = validated_data.get('bread', instance.bread)
instance.bcomment = validated_data.get('bcomment', instance.bcomment)
instance.save()
return instance
六、模型类序列化器
在上面的代码中,StudentSerializer序列化器跟模型类中Student是没有关系的。如果光写了一个StudentSerializer,在模型类中有多张表里都有name字段的话,他就会序列化所有表中的name字段。
下面使用ModelSerializer可以重构序列化类,是指定给某一个类进行使用
from rest_framework import serializers
from .models import Book
class BookSerializers(serializers.ModelSerializers):
# 需要指定跟表的对应关系
class Meta:
model = Book # 必须叫model
# 指定要序列化的字段
fields = ['name','price'] # 第一种写成一个列表指定要序列化的字段
fields = '__all__' # 第二种'__all__'将表中所有的字段全部序列化
""" 也可以使用exclude可以明确排除掉哪些字段 可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段 """
read_only_fields = ('id', 'bread', 'bcomment')
添加额外参数选项
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
extra_kwargs = {
'bread': {
'min_value': 0, 'required': True},
'bcomment': {
'min_value': 0, 'required': True},
}
depth
# 当有一个关系表中有外键时,在查询的时候会出现外键字段值为一个id号
# 想让外键字段显示详情信息就需要在
class Meta:
……
depth=1 # 这个1表示的是嵌套层数
七、习题
""" 1 定义两个表,图书和出版社表 -出版社的5个接口 -图书的5个接口 -查询的时候,出版社显示详情 -新增和修改带出版社 -价格显示成 xx元 2 新增出版社时候,addr最大8,最小3,不能以sb开头,地址不能包含名字 """
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
book_name = models.CharField(max_length=32,verbose_name='书名')
book_price = models.IntegerField(verbose_name='价钱')
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
# 查询带出版社详情方法二(直接在模型类中写)
@property
def get_publish(self):
return {
'id':self.publish.id,'publish_name':self.publish.publish_name,'publish_addr':self.publish.publish_addr}
# 查询价格方法二(直接在模型类中写)
@property
def get_book_price(self):
return str(self.book_price)+'元'
class Publish(models.Model):
publish_name = models.CharField(max_length=32,verbose_name='出版社名称')
publish_addr = models.CharField(max_length=255,verbose_name='出版社地址')
serializer.py
from rest_framework import serializers
from .models import Publish, Book
from rest_framework.exceptions import ValidationError # 需要导入异常状态包,django会捕获全局异常
class PublishModelSerializer(serializers.ModelSerializer):
class Meta:
model = Publish
fields = ['id', 'publish_name', 'publish_addr']
# extra_kwargs = {
# 'publish_addr': {'max_length': 8, 'min_length': 3, 'error_messages': {
# 'min_length': '太短',
# 'max_length': '太长'
# }}
# }
#全局钩子
def validate(self, attrs):
print(attrs)
if attrs.get('publish_addr').startswith('sb'):
raise ValidationError('不符合社会主义核心价值观')
if attrs.get('publish_name') in attrs['publish_addr']:
raise ValidationError('地址不能包含名字')
return attrs
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'book_name', 'book_price', 'publish', 'get_book_price', 'get_publish']
extra_kwargs = {
'id': {
'read_only': True},
'book_price': {
'write_only': True},
'publish': {
'write_only': True}
}
# 反序列化的时候要想只接受book_price,publish两个字段可以将其限制为write_only = True
# book_price = serializers.IntegerField(write_only=True)
# publish = serializers.IntegerField(write_only=True)
# 查询带出版社详情方法一
# publish = serializers.SerializerMethodField()
# def get_publish(self,obj):
# return {'id':obj.publish.id,'publish_name':obj.publish.publish_name,'publish_addr':obj.publish.publish_addr}
# 价格显示成 xx元方法一
# book_price = serializers.SerializerMethodField()
# def get_book_price(self,obj):
# return str(obj.book_price)+'元'
# 序列化的时候使用book_price,publish,反序列化的时候就是obook_price,opublish
# get_book_price = serializers.CharField(read_only=True)
# get_publish = serializers.CharField(read_only=True)
views.py
from django.shortcuts import render
# Create your views here.
""" 1 定义两个表,图书和出版社表 -出版社的5个接口 -图书的5个接口 -查询的时候,出版社显示详情 -新增和修改带出版社 -价格显示成 xx元 2 新增出版社时候,addr最大8,最小3,不能以sb开头,地址不能包含名字 """
from app01 import models
from rest_framework.views import APIView
from .serializers import PublishModelSerializer,BookModelSerializer
from rest_framework.response import Response
from rest_framework.exceptions import ValidationError
# 出版社 无参
class publish(APIView):
# 获取所有出版社接口
def get(self,request):
back_dic = {
'code':200,'msg':'查询成功','result':''}
res = models.Publish.objects.all()
result = PublishModelSerializer(instance=res,many=True)
back_dic['result'] = result.data
return Response(back_dic)
def post(self,request):
back_dic = {
'code': 200, 'msg': '新增成功', 'result': ''}
result = PublishModelSerializer(data=request.data)
if not result.is_valid():
return Response(result.errors)
result.save() # 保存数据
back_dic['result'] = result.data
return Response(back_dic)
# 有参
class publish_param(APIView):
def get(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '查询成功', 'result': ''}
res = models.Publish.objects.filter(**kwargs).first()
result = PublishModelSerializer(instance=res)
back_dic['result'] = result.data
return Response(back_dic)
def delete(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '删除成功'}
models.Publish.objects.filter(**kwargs).delete()
return Response(back_dic)
def put(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '修改成功', 'result': ''}
res = models.Publish.objects.filter(**kwargs).first()
result = PublishModelSerializer(instance=res,data=request.data)
if result.is_valid() ==False:
return Response(result.errors)
result.save()
back_dic['result'] = result.data
return Response(back_dic)
# 书籍 无参
class Book(APIView):
# 获取所有图书接口
def get(self, request):
back_dic = {
'code': 200, 'msg': '查询成功', 'result': ''}
res = models.Book.objects.all()
result = BookModelSerializer(instance=res, many=True)
back_dic['result'] = result.data
return Response(back_dic)
def post(self, request):
back_dic = {
'code': 200, 'msg': '新增成功', 'result': ''}
result = BookModelSerializer(data=request.data)
if not result.is_valid():
return Response(result.errors)
result.save() # 保存数据
back_dic['result'] = result.data
return Response(back_dic)
class Book_param(APIView):
def get(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '查询成功', 'result': ''}
res = models.Book.objects.filter(**kwargs).first()
result = BookModelSerializer(instance=res)
back_dic['result'] = result.data
return Response(back_dic)
def delete(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '删除成功'}
models.Book.objects.filter(**kwargs).delete()
return Response(back_dic)
def put(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '修改成功', 'result': ''}
res = models.Book.objects.filter(**kwargs).first()
result = BookModelSerializer(instance=res,data=request.data)
if result.is_valid() ==False:
return Response(result.errors)
result.save()
back_dic['result'] = result.data
return Response(back_dic)
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# 出版社
path('publish/', views.publish.as_view()),
path('publish/<int:pk>', views.publish_param.as_view()),
path('book/', views.Book.as_view()),
path('book_param/<int:pk>', views.Book_param.as_view()),
]
边栏推荐
猜你喜欢

FreeBSD bnxt以太网驱动源码阅读记录三:

智能指针-使用、避坑和实现

二分查找 && 树

专访|带着问题去学习,Apache DolphinScheduler 王福政

About the development forecast of the market outlook?2021-05-23

C语言提高篇(三)

How to solve mysql service cannot start 1069

A number of embassies and consulates abroad have issued reminders about travel to China, personal and property safety

RKMPP 在FFmpeg上实现硬编解码

mysql的case when如何用
随机推荐
Differences and concepts between software testing and hardware testing
Supervision strikes again, what about the market outlook?2021-05-22
FreeBSD bnxt以太网驱动源码阅读记录三:
如何解决1045无法登录mysql服务器
MySQL数据库设计规范
海明校验码纠错设计原理
理解TCP长连接(Keepalive)
微信小程序如何实现支付功能?看官方文档头疼(使用云函数的方式操作)「建议收藏」
Minio文件上传
C# 编译错误:Compiler Error CS1044
Linux:CentOS 7 安装MySQL5.7
政策利空对行情没有长期影响,牛市仍将继续 2021-05-19
Awesome!Alibaba interview reference guide (Songshan version) open source sharing, programmer interview must brush
关于市场后市的发展预测? 2021-05-23
栈 && 队列
WiFi Association&Omnipeek抓包分析
How to solve 1045 cannot log in to mysql server
rpm包的卸载与安装[通俗易懂]
好用的php空间,推荐国内三个优质的免费PHP空间[通俗易懂]
OpenMMLab简介