REST framework中的序列化类与Django的FormModelForm类非常相似。我们提供了一个Serializer类,它提供了一种强大的通用方法来控制响应的输出,以及一个ModelSerializer类,它为创建处理模型实例和查询集的序列化提供了有效的快捷方式。

Serializers

  序列化器允许把像查询集和模型实例这样的复杂数据转换为可以轻松渲染成JSONXML或其他内容类型的原生Python类型。序列化器还提供反序列化,在验证传入的数据之后允许解析数据转换回复杂类型。不仅仅有序列化功能,更提供了数据验证的功能(与django中的form类似)

牛刀小试:

让我们从创建一个简单的对象开始,我们可以使用下面的例子:

from datetime import datetime

class Comment(object):
def __init__(self, email, content, created=None):
self.email = email
self.content = content
self.created = created or datetime.now() comment = Comment(email='leila@example.com', content='foo bar')

然后声明一个序列化器,我们可以使用它来序列化和反序列化与Comment对象相应的数据。

声明一个序列化器看起来非常像声明一个form:

from rest_framework import serializers

class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()

1、序列化与反序列化

# 序列化(Python原生的数据类型dict)
serializer = CommentSerializer(comment)
serializer.data # {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

#转化为json类型
from rest_framework.renderers import JSONRenderer
json = JSONRenderer().render(serializer.data)
json # b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}' # 反序列化
from django.utils.six import BytesIO
from rest_framework.parsers import JSONParser stream = BytesIO(json)
data = JSONParser().parse(stream)

2、保存实例

如果我们希望能够返回基于验证数据的完整对象实例,我们需要实现其中一个或全部实现.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(**validated_data)
# return Comment.objects.create(**validated_data) # model对象 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() model对象
return instance

ps:.create().update()方法都是可选的。你可以根据你序列化器类的用例不实现、实现它们之一或都实现。

现在当我们反序列化数据的时候,基于验证过的数据我们可以调用.save()方法返回一个对象实例。

comment = serializer.save()

调用.save()方法将创建新实例或者更新现有实例,具体取决于实例化序列化器类的时候是否传递了现有实例:

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

默认情况下,序列化程序必须为所有必填字段传递值,否则会引发验证错误。你可以使用partial参数以允许部分更新

# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data,partial=True)

3、验证

反序列化数据的时候,你始终需要先调用is_valid()方法,然后再尝试去访问经过验证的数据或保存对象实例。如果发生任何验证错误,.errors属性将包含表示生成的错误消息的字典。例如:

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

字典里的每一个键都是字段名称,值是与该字段对应的任何错误消息的字符串列表。non_field_errors键可能存在,它将列出任何一般验证错误信息。non_field_errors的名称可以通过REST framework设置中的NON_FIELD_ERRORS_KEY来自定义。 当对对象列表进行序列化时,返回的错误是每个反序列化项的字典列表。

抛出无效数据的异常

.is_valid()方法使用可选的raise_exception标志,如果存在验证错误将会抛出一个serializers.ValidationError异常。

这些异常由REST framework提供的默认异常处理程序自动处理,默认情况下将返回HTTP 400 Bad Request响应。

# 如果数据无效就返回400响应
serializer.is_valid(raise_exception=True)

字段级别的验证

你可以通过向你的Serializer子类中添加.validate_<field_name>方法来指定自定义字段级别的验证。这些类似于Django表单中的.clean_<field_name>方法。

这些方法采用单个参数,即需要验证的字段值。

你的validate_<field_name>方法应该返回一个验证过的数据或者抛出一个serializers.ValidationError异常。例如:

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

注意: 如果你在序列化器中声明<field_name>的时候带有required=False参数,字段不被包含的时候这个验证步骤就不会执行。

对象级别的验证

要执行需要访问多个字段的任何其他验证,请添加一个.validate()方法到你的Serializer子类中。这个方法采用字段值字典的单个参数,如果需要应该抛出一个 ValidationError异常,或者知识返回经过验证的值。例如:

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 the start is before the stop.
"""
if data['start'] > data['finish']:
raise serializers.ValidationError("finish must occur after start")
return data

验证器

序列化器上的各个字段都可以包含验证器,通过在字段实例上声明,例如:

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])

序列化器类还可以包括应用于一组字段数据的可重用的验证器。validators给我们提供了很多很好的功能:UniqueValidator,UniqueTogetherValidator等。

这些验证器要在内部的Meta类中声明,如下所示:

UniqueTogetherValidator:(表示联合唯一)

class EventSerializer(serializers.Serializer):
name = serializers.CharField()
room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
date = serializers.DateField() class Meta:
# 每间屋子每天只能有1个活动。
validators = UniqueTogetherValidator(
queryset=Event.objects.all(),
fields=['room_number', 'date']
)

UniqueValidator:

username = serializers.CharField(
max_length=11,
min_length=11,
validators=[UniqueValidator(queryset=UserProfile.objects.all())

更多信息请参阅 validators文档

ModelSerializer

它为创建用于处理模型实例和查询集的序列化程序提供了有用的快捷实现方式。自动创建一个Serializer类,字段与model的字段一一对应。

ModelSerializer类与常规Serializer类相同,不同之处在于:

  • 它会根据模型自动生成一组字段。
  • 它会自动为序列化类生成验证器,例如unique_together验证器。
  • 它包含.create()和.update()的简单默认实现。它能够满足将post或patch上来的数据进行进行直接地创建与更新,除非有额外需求,那么就可以重载create与update方法。

声明ModelSerializer如下,在Meta中设置fields字段,系统会自动进行映射成序列化字段,省去每个字段再写一个field。

1、序列化

class CourseSerializer(serializers.ModelSerializer):
"""
课程序列化
"""class Meta:
model = models.Course
# 字段显示
fields = ['id','title','level'] #
# fields = '__all__': 表示所有字段
# exclude = ('add_time',): 除去指定的某些字段
# 只读字段 ---多个字段只读,我们可以这样设置,不用每个字段都设置read_only=True
read_only_fields=(“field_name”,) # editable=False、AutoField 默认只读,不用添加

2、关于外键

任何关系(如模型上的外键)都将映射到PrimaryKeyRelatedField(但获得外键类别的id)。除非在序列化关系文档中指定,否则默认不包括反向关系。

class CourseDetailSerializer(serializers.ModelSerializer):
"""
课程详细序列化
"""
# choice
level = serializers.CharField(source='course.get_level_display')
# one2one/fk
# 外键方式一 需要单个信息
title = serializers.ReadOnlyField(source='course.title')
# 外键方式二 需要更多信息
course=CourseSerializer(many=True) # m2m 方法一:使用SerializerMethodField(method_name=None)方法,but该方法为readonly字段。
#---当不指定method_name ,默认为get_field_name,
recommends = serializers.SerializerMethodField()
chapter = serializers.SerializerMethodField() class Meta:
model = models.CourseDetail
fields = ['course','title','img','level','slogon','why','recommends','chapter']
# 外键方式三 depth 表示应该遍历的关联深度
# depth = 1 另外访问时显示外键字段的所有信息,但是只读的,不可编辑,即新建时不能传值
def get_recommends(self,obj): # 获取推荐的所有课程
queryset = obj.recommend_courses.all()
return [{'id':row.id,'title':row.title} for row in queryset] def get_chapter(self,obj): # 获取推荐的所有课程
queryset = obj.course.chapter_set.all()
return [{'id':row.id,'name':row.name} for row in queryset]

ModelSerializer主要需要解决的2个问题:

 1,某个字段不属于指定model,它是write_only,需要用户传进来,但我们不能对它进行save( ),因为ModelSerializer是基于Model,这个字段在Model中没有对应,这个时候,我们需要重载validate!
  如在用户注册时,我们需要填写验证码,这个验证码只需要验证,不需要保存到用户这个Model中:
def validate(self, attrs):
del attrs["code"]
return attrs
2,某个字段不属于指定model,它是read_only,只需要将它序列化传递给用户,但是在这个model中,没有这个字段!我们需要用到SerializerMethodField。
  假设需要返回用户加入这个网站多久了,不可能维持这样加入的天数这样一个数据,一般会记录用户加入的时间点,然后当用户获取这个数据,我们再计算返回给它。
class UserSerializer(serializers.ModelSerializer):
days_since_joined = serializers.SerializerMethodField() class Meta:
model = User # 方法写法:get_ + 字段
def get_days_since_joined(self, obj):
# obj指这个model的对象
return (now() - obj.date_joined).days

Django Rest Framework(2)-----序列化详解(serializers)的更多相关文章

  1. Django Rest framework 之 序列化

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

  2. Django REST Framework的序列化器是什么?

    # 转载请留言联系 用Django开发RESTful风格的API存在着很多重复的步骤.详细可见:https://www.cnblogs.com/chichung/p/9933861.html 过程往往 ...

  3. Django之form表单详解

    构建一个表单 假设你想在你的网站上创建一个简单的表单,以获得用户的名字.你需要类似这样的模板: <form action="/your-name/" method=" ...

  4. Django路由配置之正则表达式详解

    正则表达式详解 urls.py from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles ...

  5. django-插件django REST framework,返回序列化的数据

    官网: http://www.django-rest-framework.org 1.安装 pip install djangorestframework 2.在setting.py中注册app 中添 ...

  6. Django restful Framework 之序列化与反序列化

    1. 首先在已建好的工程目录下新建app命名为snippets,并将snippets app以及rest_framework app加到工程目录的 INSTALLED_APPS 中去,具体如下: IN ...

  7. Django rest framework之序列化小结

       最近在DRF的序列化上踩过了不少坑,特此结合官方文档记录下,方便日后查阅. [01]前言    serializers是什么?官网是这样的”Serializers allow complex d ...

  8. rest_framework之序列化详解 06

    拿到所有的角色数据 1.urls.py 2.models.py  假设只有3个角色 3.views.py from api import models import json json只能序列化pyt ...

  9. DRF Django REST framework 之 序列化(三)

    Django 原生 serializer (序列化) 导入模块 from django.core.serializers import serialize 获取queryset 对queryset进行 ...

随机推荐

  1. mysqldump对于DB进行逻辑备份的时候,是否会备份视图呢?

    需求描述: 今天在mysql备份的书的内容,提到了mysqldump在备份数据库的时候,不会备份视图 所以,就做了个实验测试下,发现,是能够备份视图的,在此记录下. 环境描述: Mysql版本:5.5 ...

  2. Spring------Spring data jpa 定义实体类(@OneToMany等的使用)

    转载: https://course.tianmaying.com/spring-data-jpa+one-to-many#2

  3. oracle启动报ORA-03113;

    [案例] 在重启数据库过程中: SQL> startup ORACLE instance started. Total System Global Area 1.0489E+10 bytes F ...

  4. android 仿QQ手机版

    千人2群开启,欢迎大家围观打酱油,群号145667827     您当前位置 : JavaApk-安卓应用游戏源码服务专家 » QQ » Android项目源码界面超级华丽的仿QQ最新版本 Andro ...

  5. Go基础---->go的基础学习(二)

    这里记录的是go中函数的一些基础知识.道听途说终是浅,身临其境方知深. go的基础知识 一.go中函数的基础使用 package main import ( "fmt" " ...

  6. 学习Ruby你需要了解的相关知识(rvm, gem, bundle, rake, rails等)

    这篇文章主要介绍了学习Ruby你需要了解的相关知识(rvm, gem, bundle, rake, rails等),需要的朋友可以参考下     Ruby 这个就不用多说了 RVM 用于帮你安装Rub ...

  7. 【office2010】office2010安装问题的解决方案。

    今天想在公司电脑上按上一个office2010,结果出现一个问题,导致研究了一下午才解决:现总结解决方案: 安装office 2010,提示需要安装MSXML版本6.10.1129.0组件.但是在网上 ...

  8. Android动态添加布局

    //1.利用LayoutInflater的inflate动态加载XML mLinearLayout = (LinearLayout)findViewById(R.id.LinearLayout_ID) ...

  9. 常用的sass编译库

    @charset "UTF-8"; /*引进图片合并给一个变量(后面会用到这个变量)*/ $sprites:sprite-map("pwd/*.png",$sp ...

  10. 免费访问:谷歌搜索,Gmail邮箱,Chrome商店

    分享个免费的google的服务的方法 1,插件下载: http://note.youdao.com/noteshare?id=6a3e52f8d4ccf63c751eeddd625a118d 2,使用 ...