本文主要系统性的讲解django rest framwork 序列化组件的使用,基本看完可以解决工作中序列化90%的问题,写作参考官方文档https://www.django-rest-framework.org/api-guide/serializers/#modelserializer,分成如下九个部分:

  01、为什么要用序列化组件

  02、序列化组件的基本使用

  03、序列化组件常用字段

  04、序列化组件is_valid、validated_data

  05、序列化组件校验字段

  06、序列化组件.create() and .update()

  07、序列化组件ModelSerializer

  08、序列化组件构造复杂的结构

  09、序列化组件修改返回值to_representation、to_internal_value

01、为什么要用序列化组件

  我们知道前后端常用json数据结构交互, 在后端我们常想把一个对象返回给前端,但是json序列化是不能序列化对象(不过可以添加序列化参数encoder序列化原理和序列化组件差不多需要自己定义序列化类和返回的结构),所以就有了我们的序列化组件,可以自定义特定结构把对象序列化返回给前端,同时可以对前端传入的参数进行数据校验等功能。

02、序列化组件的基本使用

models

from django.db import models

# Create your models here.

class Book(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=255)
desc = models.CharField(max_length=255)
is_deleted = models.IntegerField(choices=[(1, "删除"), (0, "未删除")])
author = models.CharField(max_length=255)

serializer

from rest_framework.serializers import Serializer
from rest_framework import serializers class BookSerializer(Serializer):
id = serializers.IntegerField()
title = serializers.CharField()
desc = serializers.CharField()
is_deleted = serializers.ChoiceField(choices=[(1, "删除"), (0, "未删除")], source="get_is_deleted_display")
author = serializers.CharField()

views

from app01.models import Book
from app01.serializer import BookSerializer
from django.http import HttpResponse, JsonResponse # Create your views here. def get_books(request):
books = Book.objects.all()
se = BookSerializer(books, many=True)
return JsonResponse(se.data, safe=False)

  结果返回:

[{"id": 1, "title": "活着", "desc": "讲述一代人的人生", "is_deleted": "未删除", "author": "余华"}]

  在写法上model和serializer的写法非常相近,但内在逻辑model是与数据库表的关系映射,serializer是对对象的序列化和反序列化。

03、序列化组件常用字段

常用字段类型

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

 
 
 

  这一段引用自https://www.jianshu.com/p/26529651aa27

  在这里额外讲一个参数source,在官方文档中是这样解释的:

将用于填充字段的属性的名称。可以是仅接受self参数的方法,例如URLField(source='get_absolute_url'),也可以使用点分符号遍历属性,例如EmailField(source='user.email')。当使用点分符号序列化字段时,default如果在属性遍历期间任何对象不存在或为空,则可能需要提供一个值。

该值source='*'具有特殊含义,用于指示应将整个对象传递给该字段。这对于创建嵌套表示或对需要访问完整对象才能确定输出表示的字段很有用。

默认为字段名称。

  其中比较常用的用法:

  1、source="get_field_name_display"如上所展示,在choice字段中可以展示选项对应的解释,这中用法代表的是官方解释说的可以是仅接受self参数的方法,也就是source中可以填serializer对象可以调用的方法(方法中需要传入self),内在逻辑是这个字段会展示此方法的返回的结果。

  2、source='user.email'这种用法常在ModelSerializer的子类中,其中user为User对象,此中写法是指展示user的email属性,常用于我们想把外键对象user的属性和本对象的属性展示在同一层级,而不是下一级。

04、序列化组件is_valid、validated_data

  当我们定义好序列化器时,怎么校验传入的字段呢?那就是is_valid方法,可以根据定义序列化器的校验规则判断传入字段是否合法。

serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']}

  然后serializer.validated_data就可以获取校验过后的数据字典。

05、序列化组件校验字段

  序列化组件校验字段的方式常有三种:

  1、首先是在字段的validators属性, 其中传入一个校验方法列表如:validators=(my_validator, )其中my_validator中定义校验规则。

def multiple_of_ten(value):
if value % 10 != 0:
raise serializers.ValidationError('Not a multiple of ten') class GameRecord(serializers.Serializer):
score = IntegerField(validators=[multiple_of_ten])

  2、最常用的是定义一个validate_field_name(self, value)的函数(其中field_name指的是字段名),函数内是具体的逻辑。

from rest_framework import serializers

class BlogPostSerializer(serializers.Serializer):
title = serializers.CharField(max_length=100)
content = serializers.CharField() def validate_title(self, value):
"""
Check that the blog post is about Django.
"""
if 'django' not in value.lower():
raise serializers.ValidationError("Blog post is not about Django")
return value

  3、最后一种是定义一个validate(self, data)其中data是所有字段的键值对,所以这个校验方法是对象级别的校验。

from rest_framework import serializers

class EventSerializer(serializers.Serializer):
description = serializers.CharField(max_length=100)
start = serializers.DateTimeField()
finish = serializers.DateTimeField() def validate(self, data):
"""
Check that start is before finish.
"""
if data['start'] > data['finish']:
raise serializers.ValidationError("finish must occur after start")
return data

  当然或许当你看到这里会问why?how? 只能说源码是最好的答案。

06、序列化组件.create() and .update()

  在我们定义的序列化类中, 可以添加create和update方法,当我们有需求是根据反序列化后的数据在数据库表中创建记录或者更新某条数据,这时我们就可以在create方法和update方法中定义对应的逻辑。

class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
   def create(self, validated_data):
return Comment.objects.create(**validated_data) def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance

  接下来调用serializer.save()命令便可创建一条纪录或者更新一条记录,其中判断save时什么时候是创建什么时候是更新呢?关键在于serializer的实例化。

# .save() will create a new instance.
serializer = CommentSerializer(data=data)
serializer.save()
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data) serializer.save()

  其中当Serializer类实例化没有传入model对象时会调用create方法创建一条记录, 如果Serializer类实例化时传入了model对象就会调用update方法更新一条记录。

  有时除了反序列化的字段我们还需要其他字段怎么办呢?我们可以在save中传入参数名和值,可以在validated_data中根据参数名取到对应的值。

serializer.save(owner=request.user)

  这样我们就可以在validated_data.get("owner")就可以取到user对象了。

07、序列化组件ModelSerializer

  ModelSerializer和表单的ModelForm组件很相似,都极大简化了我们的开发,可以在内部类Meta中定义对应的model,ModelSerializer就会自动生成model字段对应的Field不用我们定义。

class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']

   其中fields中定义序列化的字段,如果是全部字段就写__all__, 上述例子我们没有定义具体的字段,ModelSerializer帮我们自动生成了 'id', 'account_name', 'users', 'created'的Field。

08、序列化组件构造复杂的结构

  以下是个存在一对多和多对多字段的序列化器

serializer

from res_framework import serializers

#这个类用于被实例化,多对多字段这么写
class AuthorSerializer(serializers.Serializer):
id = serializers.Charfield()
name = serializers.Charfield()
age = serializers.Charfield() #传给views.py的主类
class BookSerializer(serializers.Serializer):
name = serializers.Charfield()
#source 可以指定字段 , id是要序列化的表名。
id = serializers.CharField(source='nid')
#,source后字段用.的方式可以跨表查询。
publish = serializer.CharField(source='publish.email')
'''
如果在models.py的book类中定义一个test方法。
def test(self):
return str(self.price)+self.name
'''
# 返回的结果就会有xx字段,souce不但可以指定表模型字段,还可以指定模型表方法,并且赋值给xx变量
xx = serializers.Charfield(source='test') #外键的实现方法:
#一对多字段
#如果要通过外键字段返回出版社的所有信息,包括id,name,email...
#obj是当前循环序列化到的数据对象
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
return {’id‘:obj.publish.pk,'name':obj.publish.name} #多对多字段
#所有作者的详情,也展示出来
authors = serializers.SerializermethodFiled()
def get_authors(self,obj):
author_list = obj.authors.all()
author_ser = AuthorSerializer(author_list,many=True)
return author_ser.data

views

from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models class BookView(APIview):
def get(self,request,*args,**kwargs):
#获取所有图书数据
response = {'status':100,'msg':'获取成功'}
book_list = models.Book.objects.all()
#实例化BookSerializer类,把要序列化的数据book_list传入
#如果要序列化querySet对象,一定要加many = True
book_ser = BookSerializer(book_list,many=True)
#把序列化后的数据book_ser.data 拿出来放到response字典中返回给客户端
response['data'] = book_ser.data
return Response(response)

如果使用ModelSerializer:

serializer

from app01 import models
class PublishSerializer(serializers.ModelSerializer):
class Meta: #固定写法
# 指定要序列化Book表
model = models.Book
#指定要序列化的字段
fields = ['nid','name']
#序列化所有字段
fileds ='__all__‘
#要排除的字段(不能与fileds连用)
# exclude = ['name','price']
#深度判定
depth = 1
#如果要不按照父类的来,想要自己定义显示的字段的话,自己定义一个,覆盖掉父类的字段属性。
publish = serializers.SerializerMethodField() #一对多字段
def get_publish(self,obj):
return {’id‘:obj.publish.pk,'name':obj.publish.name}

  此段摘自https://blog.csdn.net/qq_36019490/article/details/90339490

  这里额外解释一下depth这个参数:在对象外键另一对象,另一对象又外键另一对象以此类推,depth的作用就是可以决定序列化时的外键深度。

  复杂序列化器的要点在于,serializers.SerializerMethodField()和get_field_name的使用获取自己想得到的字段值,还有source的使用,上面有讲。

09、序列化组件修改返回值to_representation、to_internal_value

  to_representation(self, instance):如果序列化器定义了此方法,可以改变序列化对象data的值,也就是serializer.data的值,你可以根据自己的业务场景去重新构造返回值。

def to_representation(self, instance):
"""Convert `username` to lowercase."""
ret = super().to_representation(instance)
ret['username'] = ret['username'].lower()
return ret

  to_internal_value(self, data): data为未经校验的数据字段, 此方法可以实现校验和修改反序列化后的值,然后返回。如果不想修改反序列化后的值只是做校验的话,完全可以使用validate方法替代。

def to_internal_value(self, value):
if value == None:
return 0
return value

  总而言之,这两个方法一个是用于重新构造validated_data并返回,一个用于重新构造serializer.data的值并返回。

Django序列化组件Serializers详解的更多相关文章

  1. Serializers 序列化组件——ModelSerializer详解

    前面学习Serializers用法时,发现所有的序列化都与我们的模型紧密相关. django_restframework也给我提供了跟模型紧密相关的序列化器——ModelSerializer. 它会根 ...

  2. Django序列化组件与数据批量操作与简单使用Forms组件

    目录 SweetAlert前端插件 Django自带的序列化组件 批量数据操作 分页器与推导流程 Forms组件之创建 Forms组件之数据校验 Forms组件之渲染标签 Forms组件之信息展示 S ...

  3. Django框架 之 querySet详解

    Django框架 之 querySet详解 浏览目录 可切片 可迭代 惰性查询 缓存机制 exists()与iterator()方法 QuerySet 可切片 使用Python 的切片语法来限制查询集 ...

  4. [安卓基础] 009.组件Activity详解

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  5. 第15.10节 PyQt(Python+Qt)入门学习:Qt Designer可视化设计界面组件与QWidget类相关的组件属性详解

    PyQt学习有阵子了,对章节的骨架基本考虑好了,准备本节就写组件的属性的,结果一是日常工作繁忙,经常晚上还要加班,二是Qt的组件属性很多,只能逐一学习.研究和整理,花的时间有点长,不过终于将可视化设计 ...

  6. Django框架第九篇--Django和Ajax、序列化组件(serializers)、自定义分页器、模型表choice参数

    Django和Ajax 一.什么是Ajax AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”.即使用Javascript语 ...

  7. Django学习笔记之Django Form表单详解

    知识预览 构建一个表单 在Django 中构建一个表单 Django Form 类详解 使用表单模板 回到顶部 构建一个表单 假设你想在你的网站上创建一个简单的表单,以获得用户的名字.你需要类似这样的 ...

  8. Django中数据传输编码格式、ajax发送json数据、ajax发送文件、django序列化组件、ajax结合sweetalert做二次弹窗、批量增加数据

    前后端传输数据的编码格式(contentType) 提交post请求的两种方式: form表单 ajax请求 前后端传输数据的编码格式 urlencoded formdata(form表单里的) ja ...

  9. django中request对象详解(转载)

    django中的request对象详解 Request 我们知道当URLconf文件匹配到用户输入的路径后,会调用对应的view函数,并将  HttpRequest对象  作为第一个参数传入该函数. ...

随机推荐

  1. web安全之跨站脚本漏洞(XSS)

    XSS(跨站脚本)概述以及pikachu上的实验操作 Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS. XSS ...

  2. 【部分】Asp.Net Mvc 控制器与视图的数据传递

    原文:https://www.cnblogs.com/lsgsanxiao/p/5105639.html 数据传递也就是控制器和视图之间的交互,比如在视图中提交的数据,在控制器怎么获取,或者控制器从业 ...

  3. C# 模型赋值

    /// <summary> /// 模型赋值 /// </summary> /// <param name="target">目标</pa ...

  4. Nginx平滑升级详细步骤-113p.cn

    认识平滑升级 有时候我们需要对Nginx版本进行升级以满足运维人员对其功能的需求,例如添加xxx模块,需要xxx功能,而此时Nginx又在跑着业务无法停掉,这时我们就只能平滑升级了. 平滑升级原理 N ...

  5. idea 链接 Tomcat 出现的错误 Application server libraries not found

    红色字体是重点 好久好久没有上来了.一直忙于工作没事有时间进行总结. 最近在家隔离期间发现了一个好玩的游戏率土之滨  , 玩的不错和大盟主混的很好.在给盟里做考勤任务的时候发现很麻烦还需要用Excel ...

  6. Python-数据结构-最全六种排序代码实现

    1.冒泡排序 def bubble_sort(alist): """冒泡排序""" n = len(alist) for j in rang ...

  7. Netty 源码解析(六): Channel 的 register 操作

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第六篇. 接下来的时间灯塔君持续更新Netty系列一共九篇   Netty 源码解析(一 ):开始 Netty ...

  8. Xenon's Attack on the Gangs(树规)

    题干 Input Output Example Test 1: Test 2: 3 5 1 2 1 2 2 3 1 3 1 4 3 5 3 10 Tips 译成人话 给n个结点,n-1条无向边.即一棵 ...

  9. Django---drf第一天---作业

    1 图书的5个接口写完(使用序列化组件) urls.py from django.contrib import admin from django.urls import path, re_path ...

  10. 微服务架构中的BFF到底是啥?

    在<技术中台与业务中台都是啥玩意>一文中留下一个问题:BFF是啥?为啥在API网关和业务中台之间加入了一层BFF?考虑到在实际工作中,我的大部分同事都问过这个问题,这里我也总结一下进行答复 ...