Django Rest Framework(2)-----序列化详解(serializers)

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=‘[email protected]‘, 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‘: ‘[email protected]‘, ‘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":"[email protected]","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

原文地址:https://www.cnblogs.com/freely/p/10305434.html

时间: 2024-07-30 16:16:59

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

Django之HttpServer服务器分析详解

大家知道,软件的正向工程,是从软件的需求获取开始,大概经历需求分析,概要分析,领域分析,设计分析,详细设计,代码实现,部署,实施这几个步骤,最终交付给用户使用.而在某些时候,比如某个软件产品是用PHP开发的,因为某些原因,我们想移植到JAVA平台去.或者某公司看到某个软件的市场前景很好,想COPY它的主要功能,然后经过加工润色后推出一个具有相同功能,更好用户体验或更多功能的软件.或者单纯的以研究软件的结构.设计思想为目的.基于这些需求,我们需要逆向工程.正向工程是一个从过程导出结果的步骤,而逆向

django的crsf机制防御详解及在前后端分离中post数据到django-vue

django的crsf机制防御详解及在前后端分离中post数据到django 更新于: 2018-07-28 |  分类于 django CSRF(Cross Site Request Forgery) 跨站点伪造请求 某个用户已经登陆了你的网站,另外有一个恶意的网站有一个指向你网站的链接,那么当用户点击这个链接时,就会请求你的网站,但是你的网站以为是用户发来的请求,这时恶意网站就得逞了. django的应对措施 用户在post请求时,发送给用户一个token,然后在django内部实现了一个校

序列化详解

Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程.   2.什么情况下需要序列化 a)当你想把的内存中的对象保存到一个文件中或者数据库中时候:b)当你想用套接字在网络上传送对象的时候:c)当你想通过RMI传输对象的时候: 3.如何实现序列化 将需要序列化的类实现Serializable接口就可以了,Seriali

076:【Django数据库】F表达式详解

F表达式详解: F表达式 是用来优化 ORM 操作数据库的.比如我们要将公司所有员工的薪水都增加1000元,如果按照正常的流程,应该是先从数据库中提取所有的员工工资到Python内存中,然后使用Python代码在员工工资的基础之上增加1000元,最后再保存到数据库中.这里面涉及的流程就是,首先从数据库中提取数据到Python内存中,然后在Python内存中做完运算,之后再保存到数据库中.示例代码如下: employees = Employee.objects.all() for employee

079:【Django数据库】QuerySet API详解-filter、exclude、annotate

QuerySet API详解-filter.exclude.annotate: 在使用 QuerySet 进行查找操作的时候,可以提供多种操作.比如过滤完后还要根据某个字段进行排序,那么这一系列的操作我们可以通过一个非常流畅的 链式调用 的方式进行.比如要从文章表中获取标题为 123 ,并且提取后要将结果根据发布的时间进行排序,那么可以使用以下方式来完成: articles = Article.objects.filter(title='123').order_by('create_time')

080:【Django数据库】QuerySet API详解-order_by:

QuerySet API详解-order_by: order_by:指定将查询的结果根据某个字段进行排序.如果要倒叙排序,那么可以在这个字段的前面加一个负号.示例代码如下: # 时间从前往回排: # orders = BookOrder.objects.order_by("create_time") # 时间从后往前排(与上面相反): orders = BookOrder.objects.order_by("-create_time") # 时间从后往前排,如果时间

django rest framework之序列化

首先找到models文件,然后里面写上内容,自定义 class UserGroup(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): name = models.CharField(verbose_name="姓名",max_length=255) age = models.IntegerField(verbose_name="年龄") choic

Django REST framework之序列化组件以及源码分析+全局、局部Hook

序列化两大功能 a.对queryset类型进行序列化 b.对用户请求的数据进行校验 a.对queryset类型进行序列化 举例说明: 表设计 1 from django.db import models 2 3 4 class UserGroup(models.Model): 5 title = models.CharField(max_length=32) 6 7 8 class UserInfo(models.Model): 9 user_type_choices = ( 10 (1, '普

DRF(Django Rest Framework)序列化组件接口使用和接口设计--!GET接口设计!

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