Serializers

serializers.py

序列化器


串行器允许诸如查询集和模型实例复杂的数据转换为可随后被容易地呈现到机Python数据类型JSONXML或其他内容类型。序列化器还提供反序列化,允许解析的数据在首次验证传入数据后转换为复杂类型。

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

声明序列化器

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

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对象相对应的数据。

声明一个串行器看起来非常类似于声明一个窗体:

from rest_framework import serializers

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

序列化对象

我们现在可以使用CommentSerializer序列化注释或注释列表。再次,使用Serializer类看起来很像使用Form类。

serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

此时,我们将模型实例转换为Python本机数据类型。为了完成序列化过程,我们将数据转化为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"}'

反序列化对象

反序列化是类似的。首先我们将一个流解析为Python本机数据类型...

from django.utils.six import BytesIO
from rest_framework.parsers import JSONParser

stream = BytesIO(json)
data = JSONParser().parse(stream)

...然后我们将这些本机数据类型恢复到已验证数据的字典中。

serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}

保存实例

如果我们希望能够返回基于经过验证的数据完整的对象情况下,我们需要实现的一个或两个.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)

    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)
        return instance

如果您的对象实例对应于Django模型,您还需要确保这些方法将对象保存到数据库。例如,如果Comment是Django模型,方法可能如下所示:

    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

现在反序列化数据时,我们可以.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)

无论是.create().update()方法是可选的。您可以根据您的串行器类的用例来实现它们之一,一个或两者。

传递附加属性到.save()

有时你会希望你的视图代码能够在保存实例时注入额外的数据。此附加数据可能包括当前用户,当前时间或不是请求数据一部分的其他信息。

您可以通过在调用时添加其他关键字参数来实现.save()。例如:

serializer.save(owner=request.user)

任何其他关键字参数将被包含在validated_data参数中.create()或被.update()调用时。

.save()直接覆盖

在某些情况下.create().update()方法名称可能无意义。例如,在联系表单中,我们可能不会创建新的实例,而是发送电子邮件或其他消息。

在这些情况下,您可以选择.save()直接覆盖,因为更可读和有意义。

例如:

class ContactForm(serializers.Serializer):
    email = serializers.EmailField()
    message = serializers.CharField()

    def save(self):
        email = self.validated_data['email']
        message = self.validated_data['message']
        send_email(from=email, message=message)

请注意,在上述情况下,我们现在必须.validated_data直接访问serializer 属性。

验证

反序列化数据时,您始终需要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可以使用NON_FIELD_ERRORS_KEYREST框架设置来定制密钥的名称。

当对项目列表进行反序列化时,将作为代表每个反序列化项目的字典列表返回错误。

提出无效数据的异常

.is_valid()方法使用可选raise_exception标志,serializers.ValidationError如果存在验证错误,则会引发异常。

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

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
场级验证

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

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

您的validate_<field_name>方法应返回验证的值或提出a 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])
    ...

序列化器类还可以包括应用于整套现场数据的可重用验证器。这些验证器包含在内部Meta类上声明它们,如下所示:

class EventSerializer(serializers.Serializer):
    name = serializers.CharField()
    room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
    date = serializers.DateField()

    class Meta:
        # Each room only has one event per day.
        validators = UniqueTogetherValidator(
            queryset=Event.objects.all(),
            fields=['room_number', 'date']
        )

有关更多信息,请参阅验证器文档

访问初始数据和实例

将初始对象或查询集传递给序列化器实例时,对象将作为可用.instance。如果没有初始对象被传递,那么.instance属性将是None

将数据传递给序列化器实例时,未修改的数据将作为可用.initial_data。如果data关键字参数未被传递,则该.initial_data属性将不存在。

部分更新

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

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

处理嵌套对象

以前的示例适用于处理只有简单数据类型的对象,但有时我们还需要能够表示更复杂的对象,其中对象的某些属性可能不是简单的数据类型,如字符串,日期或整数。

所述Serializer类本身的类型Field,并且可以用于表示其中一个对象类型嵌套在另一个关系。

class UserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    username = serializers.CharField(max_length=100)

class CommentSerializer(serializers.Serializer):
    user = UserSerializer()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

如果嵌套表示可以选择接受该None值,则应将该required=False标志传递给嵌套的序列化程序。

class CommentSerializer(serializers.Serializer):
    user = UserSerializer(required=False)  # May be an anonymous user.
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

类似地,如果嵌套表示应该是项目列表,则应该将该many=True标志传递给嵌套的序列化。

class CommentSerializer(serializers.Serializer):
    user = UserSerializer(required=False)
    edits = EditItemSerializer(many=True)  # A nested list of 'edit' items.
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

可写嵌套表示

当处理支持反序列化数据的嵌套表示时,嵌套对象的任何错误都嵌套在嵌套对象的字段名下。

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

类似地,.validated_data属性将包括嵌套数据结构。

编写.create()嵌套表示方法

如果您支持可写嵌套表示,则需要编写.create().update()处理保存多个对象的方法。

以下示例演示如何处理创建具有嵌套概要文件对象的用户。

class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ('username', 'email', 'profile')

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user
编写.update()嵌套表示方法

对于更新,您将需要仔细考虑如何处理关系的更新。例如,如果关系的数据是否None提供,则应发生以下哪项?

  • NULL在数据库中设置关系。
  • 删除关联的实例。
  • 忽略数据,并保留实例。
  • 提高验证错误。

下面是update()我们上一课的方法的一个例子UserSerializer

    def update(self, instance, validated_data):
        profile_data = validated_data.pop('profile')
        # Unless the application properly enforces that this field is
        # always set, the follow could raise a `DoesNotExist`, which
        # would need to be handled.
        profile = instance.profile

        instance.username = validated_data.get('username', instance.username)
        instance.email = validated_data.get('email', instance.email)
        instance.save()

        profile.is_premium_member = profile_data.get(
            'is_premium_member',
            profile.is_premium_member
        )
        profile.has_support_contract = profile_data.get(
            'has_support_contract',
            profile.has_support_contract
         )
        profile.save()

        return instance

因为嵌套创建和更新的行为可能不明确,并且可能需要相关模型之间的复杂依赖关系,所以REST框架3要求您始终明确地编写这些方法。默认ModelSerializer.create().update()方法不包括对可写嵌套表示的支持。

提供自动支持某种类型的自动可写嵌套表示的第三方包可能与3.1版本一起被释放。

在串行器中保存多个相关实例的另一种方法是编写处理创建正确实例的自定义模型管理器类。

例如,假设我们想确保User实例和Profile实例总是一起创建为一对。我们可能会写一个类似这样的自定义管理器类:

class UserManager(models.Manager):
    ...

    def create(self, username, email, is_premium_member=False, has_support_contract=False):
        user = User(username=username, email=email)
        user.save()
        profile = Profile(
            user=user,
            is_premium_member=is_premium_member,
            has_support_contract=has_support_contract
        )
        profile.save()
        return user

这个管理器类现在更好地封装了用户实例和配置文件实例总是在同一时间创建的。我们.create()在serializer类上的方法现在可以重写,以使用新的管理器方法。

def create(self, validated_data):
    return User.objects.create(
        username=validated_data['username'],
        email=validated_data['email']
        is_premium_member=validated_data['profile']['is_premium_member']
        has_support_contract=validated_data['profile']['has_support_contract']
    )

有关此方法的更多详细信息,请参阅有关模型管理器的Django文档,以及使用模型和管理器类的此博客

处理多个对象

Serializer班还可以处理序列化或反序列化对象的列表。

序列化多个对象

要序列化查询或列表对象而不是单个对象实例,应many=True在实例化序列化程序时传递该标志。然后,您可以传递一个查询列表或要序列化的对象列表。

queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
# [
#     {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},
#     {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},
#     {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
# ]
反序列化多个对象

反序列化多个对象的默认行为是支持多个对象创建,但不支持多个对象更新。有关如何支持或自定义这些情况的更多信息,请参阅下面的ListSerializer文档。

包括额外的上下文

在某些情况下,除了要序列化的对象之外,还需要为序列化程序提供额外的上下文。一个常见的情况是,如果您使用包含超链接关系的序列化程序,这需要序列化程序才能访问当前请求,以便它可以正确生成完全限定的URL。

您可以通过context在实例化序列化程序时传递参数来提供任意的附加上下文。例如:

serializer = AccountSerializer(account, context={'request': request})
serializer.data
# {'id': 6, 'owner': u'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}

上下文字典可以在任何序列化器字段逻辑中使用,例如.to_representation()通过访问self.context属性的自定义方法。


ModelSerializer

通常你会想要与Django模型定义紧密相连的序列化器类。

ModelSerializer类提供了一个快捷方式,可以让你自动创建一个Serializer类对应于模型字段的字段。

ModelSerializer班是一样的常规Serializer类,不同之处在于

  • 它将根据模型自动为您生成一组字段。
  • 它将自动生成序列化程序的验证器,如unique_together验证器。
  • 它包括简单的默认实现.create().update()

声明ModelSerializer如下:

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

默认情况下,类上的所有模型字段将映射到相应的序列化程序字段。

任何关系,如模型上的外键都将被映射到PrimaryKeyRelatedField。默认情况下不包括反向关系,除非在序列化器关系文档中指定明确包含。

检查一个ModelSerializer

Serializer类生成有用的详细表示字符串,可以让您完全检查其字段的状态。这在使用ModelSerializers您想要确定为您自动创建哪些字段和验证器的位置时特别有用。

要这样做,打开Django shell,使用python manage.py shell,然后导入serializer类,实例化,并打印对象表示...

>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))
AccountSerializer():
    id = IntegerField(label='ID', read_only=True)
    name = CharField(allow_blank=True, max_length=100, required=False)
    owner = PrimaryKeyRelatedField(queryset=User.objects.all())

指定要包括的字段

如果您只希望在模型序列化程序中使用默认字段的一部分,则可以使用fieldsexclude选项来执行此操作,就像使用它一样ModelForm。强烈建议您使用fields属性显式设置应序列化的所有字段。当您的型号更改时,这将不太可能导致无意中暴露数据。

例如:

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

您还可以将fields属性设置为特殊值,'__all__'以指示应使用模型中的所有字段。

例如:

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = '__all__'

您可以将exclude属性设置为要从序列化程序中排除的字段列表。

例如:

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        exclude = ('users',)

在上面的例子中,如果Account模型具有3个字段account_nameuserscreated,这将导致在字段account_namecreated被序列化。

在名称fieldsexclude属性,通常会映射到模型上的模型类的字段。

或者,fields选项中的名称可以映射到不存在模型类上的参数的属性或方法。

指定嵌套序列化

默认ModelSerializer使用主键进行关系,但您也可以使用以下depth选项轻松生成嵌套表示:

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

depth选项应设置为一个整数值,指示在还原到平面表示之前应该遍历的关系深度。

如果要自定义序列化的方式,您需要自己定义该字段。

明确指定字段

您可以ModelSerializer通过在类上声明字段来添加额外的字段或覆盖默认字段,就像您对Serializer类进行的一样。

class AccountSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    groups = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Account

额外的字段可以对应于模型上的任何属性或可调用。

指定只读字段

您可能希望将多个字段指定为只读。而不是使用read_only=True属性显式添加每个字段,您可以使用快捷方式Meta选项read_only_fields

该选项应该是字段名称的列表或元组,并声明如下:

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

模型字段已editable=False设置,AutoField字段将默认设置为只读,不需要添加到该read_only_fields选项。


注意:有一种特殊情况,其中只读字段是unique_together模型级别的约束的一部分。在这种情况下,串行器类需要该字段才能验证约束,但也不能由用户编辑。

处理此问题的正确方法是在序列化程序上显式指定该字段,同时提供read_only=Truedefault=…关键字参数。

一个例子Userunique_together与当前已认证的另一个标识符的只读关系。在这种情况下,您将声明用户字段:

user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())

有关UniqueTogetherValidatorCurrentUserDefault类的详细信息,请查看验证器文档


附加关键字参数

还有一个快捷方式,可以使用该extra_kwargs选项在字段上指定任意附加的关键字参数。在这种情况下read_only_fields,这意味着您不需要在序列化程序上显式声明该字段。

此选项是字典,将字段名称映射到关键字参数的字典。例如:

class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email', 'username', 'password')
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = User(
            email=validated_data['email'],
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

关系领域

序列化模型实例时,您可以选择多种不同的方式来表示关系。默认表示法ModelSerializer是使用相关实例的主键。

替代表示包括使用超链接序列化,序列化完整嵌套表示,或使用自定义表示序列化。

有关完整的详细信息,请参阅serializer关系文档。

自定义字段映射

ModelSerializer类还公开了一个可以覆盖的API,以便在实例化序列化程序时改变序列化程序字段的自动确定。

通常情况下,如果ModelSerializer您没有生成默认情况下需要的字段,那么您应该将它们显式添加到类中,或者直接使用常规Serializer类。但是在某些情况下,您可能需要创建一个新的基类,以定义为任何给定模型创建序列化器字段的方式。

.serializer_field_mapping

将Django模型类映射到REST框架序列化器类。您可以覆盖此映射以更改每个模型类应使用的默认序列化器类。

该属性应该是序列化器字段类,默认情况下用于关系字段。

对于ModelSerializer此默认为PrimaryKeyRelatedField

对于HyperlinkedModelSerializer此默认为serializers.HyperlinkedRelatedField

serializer_url_field

串行器字段类,应该用于url串行器上的任何字段。

默认为 serializers.HyperlinkedIdentityField

serializer_choice_field

串行器字段类,应该用于串行器上的任何选择字段。

默认为 serializers.ChoiceField

field_class和field_kwargs API

调用以下方法来确定应该自动包含在序列化程序中的每个字段的类和关键字参数。这些方法中的每一个都应该返回两个元组(field_class, field_kwargs)

.build_standard_field(self, field_name, model_field)

被称为生成映射到标准模型字段的序列化器字段。

默认实现根据该serializer_field_mapping属性返回一个串行化器类。

.build_relational_field(self, field_name, relation_info)

被称为生成映射到关系模型字段的序列化器字段。

默认实现根据该serializer_relational_field属性返回一个串行化器类。

relation_info参数是一个名为元组,包含model_fieldrelated_modelto_manyhas_through_model属性。

.build_nested_field(self, field_name, relation_info, nested_depth)

被调用生成一个序列化器字段,映射到关系模型字段,当该depth选项被设置。

默认的实现动态地创建基于任何一个嵌套的序列化器类ModelSerializerHyperlinkedModelSerializer

nested_depth会的价值depth选择,减之一。

relation_info参数是一个名为元组,包含model_fieldrelated_modelto_manyhas_through_model属性。

.build_property_field(self, field_name, model_class)

被调用生成一个序列化器字段,它映射到模型类的属性或零参数方法。

默认实现返回一个ReadOnlyField类。

.build_url_field(self, field_name, model_class)

被称为为序列化器自己的url字段生成一个串行化器字段。默认实现返回一个HyperlinkedIdentityField类。

.build_unknown_field(self, field_name, model_class)

当字段名称未映射到任何模型字段或模型属性时调用。默认实现引发错误,尽管子类可能会自定义此行为。


HyperlinkedModelSerializer

HyperlinkedModelSerializer类是类似于ModelSerializer不同之处在于它使用的超链接来表示的关系,而不是主键类。

默认情况下,序列化程序将包含一个url字段而不是主键字段。

url字段将使用HyperlinkedIdentityFieldserializer字段来表示,模型上的任何关系将使用HyperlinkedRelatedFieldserializer字段来表示。

您可以通过将主键添加到fields选项中来显式包含,例如:

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ('url', 'id', 'account_name', 'users', 'created')

绝对和相对URL

实例化时HyperlinkedModelSerializer,必须request在串行器上下文中包含当前值 ,例如:

serializer = AccountSerializer(queryset, context={'request': request})

这样做将确保超链接可以包含适当的主机名,以便生成的表达式使用完全限定的URL,例如:

http://api.example.com/accounts/1/

而不是相对URL,例如:

/accounts/1/

如果你希望使用相对URL,你应该明确地传递{'request': None}在串行环境。

如何确定超链接视图

需要一种确定哪些视图应用于超链接到模型实例的方法。

默认情况下,超级链接预期对应于与样式匹配的视图名称'{model_name}-detail',并通过pk关键字参数查找实例。

您可以通过使用重写URL字段视图名称和查找字段,或两者中,view_namelookup_field在选项extra_kwargs设置,如下所示:

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ('account_url', 'account_name', 'users', 'created')
        extra_kwargs = {
            'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},
            'users': {'lookup_field': 'username'}
        }

或者,您可以显式设置串行器上的字段。例如:

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(
        view_name='accounts',
        lookup_field='slug'
    )
    users = serializers.HyperlinkedRelatedField(
        view_name='user-detail',
        lookup_field='username',
        many=True,
        read_only=True
    )

    class Meta:
        model = Account
        fields = ('url', 'account_name', 'users', 'created')

提示:正确匹配超链接表示和您的URL conf有时可能会有点困难。打印repr一个HyperlinkedModelSerializer实例是一个特别有用的方式来检查哪些视图名称和查找字段的关系预期映射也是。


更改URL字段名称

URL字段的名称默认为“url”。您可以通过使用该URL_FIELD_NAME设置覆盖全局。


ListSerializer

ListSerializer类提供了序列化和一次验证多个对象的行为。你不会通常需要使用ListSerializer直接,而是应该简单地传递many=True实例化一个序列化时。

当串行器被实例化并被many=True传递时,ListSerializer将创建一个实例。然后,序列化器类将成为父级的子级ListSerializer

以下参数也可以传递给通过的ListSerializer字段或序列化many=True

allow_empty

这是True默认情况下,但False如果您不想将空列表作为有效输入,可以设置为。

自定义ListSerializer行为

这里一些使用情况下,您可能希望定制的ListSerializer行为。例如:

  • 您希望提供列表的特定验证,例如检查一个元素是否与列表中的另一个元素冲突。
  • 您要自定义多个对象的创建或更新行为。

对于这些情况,您可以many=True通过使用list_serializer_classserializerMeta类上的选项来修改传递过程中使用的类。

例如:

class CustomListSerializer(serializers.ListSerializer):
    ...

class CustomSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = CustomListSerializer
自定义多个创建

多个对象创建的默认实现是简单地调用.create()列表中的每个项目。如果要自定义此行为,则需要自定义传递时使用的类上的.create()方法。ListSerializermany=True

例如:

class BookListSerializer(serializers.ListSerializer):
    def create(self, validated_data):
        books = [Book(**item) for item in validated_data]
        return Book.objects.bulk_create(books)

class BookSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = BookListSerializer
自定义多个更新

默认情况下,ListSerializer该类不支持多个更新。这是因为插入和删除应该预期的行为是不明确的。

要支持多个更新,您需要明确地这样做。编写多个更新代码时,请务必注意以下几点:

  • 如何确定数据列表中每个项目应该更新哪个实例?
  • 如何处理插入?它们是无效的,还是创建新对象?
  • 移除应如何处理?他们是否暗示删除对象,还是删除关系?他们应该默默无视,还是无效?
  • 订购如何处理?改变两个项目的位置是否意味着任何状态改变或被忽略?

您将需要向id实例序列化程序添加一个显式字段。默认的隐式生成的id字段被标记为read_only。这导致它在更新时被删除。一旦你明确声明它,它将在列表序列化程序的update方法中可用。

以下是您可以选择实施多个更新的示例:

class BookListSerializer(serializers.ListSerializer):
    def update(self, instance, validated_data):
        # Maps for id->instance and id->data item.
        book_mapping = {book.id: book for book in instance}
        data_mapping = {item['id']: item for item in validated_data}

        # Perform creations and updates.
        ret = []
        for book_id, data in data_mapping.items():
            book = book_mapping.get(book_id, None)
            if book is None:
                ret.append(self.child.create(data))
            else:
                ret.append(self.child.update(book, data))

        # Perform deletions.
        for book_id, book in book_mapping.items():
            if book_id not in data_mapping:
                book.delete()

        return ret

class BookSerializer(serializers.Serializer):
    # We need to identify elements in the list using their primary key,
    # so use a writable field here, rather than the default which would be read-only.
    id = serializers.IntegerField()

    ...
    id = serializers.IntegerField(required=False)

    class Meta:
        list_serializer_class = BookListSerializer

类似于allow_add_removeREST框架2中存在的行为,可能会在3.1版本旁边包含第三方软件包,以提供对多个更新操作的一些自动支持。

自定义ListSerializer初始化

当一个串行器many=True被实例化时,我们需要确定哪些参数和关键字参数应该被传递给.__init__()Serializer类和父ListSerializer类的方法。

默认实现是将所有参数传递给两个类,除了validators和任何自定义关键字参数,这两个参数都假定用于子序列化器类。

偶尔,您可能需要明确指定当many=True传递子代和父类时应如何实例化。您可以使用many_init类方法来执行此操作。

    @classmethod
    def many_init(cls, *args, **kwargs):
        # Instantiate the child serializer.
        kwargs['child'] = cls()
        # Instantiate the parent list serializer.
        return CustomListSerializer(*args, **kwargs)

BaseSerializer

BaseSerializer 可以轻松支持替代序列化和反序列化样式的类。

该类实现与类相同的基本API Serializer

  • .data - 返回传出的原始表示。
  • .is_valid() - 反序列化和验证传入数据。
  • .validated_data - 返回验证的传入数据。
  • .errors - 返回验证期间的任何错误。
  • .save() - 将验证的数据保存到对象实例中。

有四种可以被覆盖的方法,这取决于你希望序列化器类支持哪些功能:

  • .to_representation() - 覆盖此功能以支持序列化,以进行读取操作。
  • .to_internal_value() - 覆盖此操作以支持反序列化,用于写入操作。
  • .create().update()- 覆盖其中一个或两个以支持保存实例。

因为这个类提供与类相同的接口,所以Serializer您可以使用它与现有的基于类的视图完全一样的常规SerializerModelSerializer

在这样做时,您会注意到的唯一的区别是BaseSerializer类不会在可浏览的API中生成HTML表单。这是因为他们返回的数据不包括所有字段信息,这将允许每个字段被渲染成一个合适的HTML输入。

只读BaseSerializer

要使用BaseSerializer类实现只读序列化程序,我们只需要覆盖该.to_representation()方法。我们来看一个使用简单的Django模型的例子:

class HighScore(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    player_name = models.CharField(max_length=10)
    score = models.IntegerField()

创建一个只读序列化器来将HighScore实例转换为原始数据类型很简单。

class HighScoreSerializer(serializers.BaseSerializer):
    def to_representation(self, obj):
        return {
            'score': obj.score,
            'player_name': obj.player_name
        }

我们现在可以使用这个类序列化单个HighScore实例:

@api_view(['GET'])
def high_score(request, pk):
    instance = HighScore.objects.get(pk=pk)
    serializer = HighScoreSerializer(instance)
    return Response(serializer.data)

或者使用它来序列化多个实例:

@api_view(['GET'])
def all_high_scores(request):
    queryset = HighScore.objects.order_by('-score')
    serializer = HighScoreSerializer(queryset, many=True)
    return Response(serializer.data)
读写BaseSerializer

要创建一个读写序列化程序,我们首先需要实现一个.to_internal_value()方法。此方法返回将用于构造对象实例的验证值,ValidationError如果提供的数据格式不正确,则可能会生成。

一旦你已经实现.to_internal_value(),基本验证API将可在串行器,你将能够使用.is_valid().validated_data.errors

如果你也想支持.save()你还需要落实的一个或两个.create().update()方法。

以下是我们之前的完整示例HighScoreSerializer,该示例已更新,以支持读取和写入操作。

class HighScoreSerializer(serializers.BaseSerializer):
    def to_internal_value(self, data):
        score = data.get('score')
        player_name = data.get('player_name')

        # Perform the data validation.
        if not score:
            raise ValidationError({
                'score': 'This field is required.'
            })
        if not player_name:
            raise ValidationError({
                'player_name': 'This field is required.'
            })
        if len(player_name) > 10:
            raise ValidationError({
                'player_name': 'May not be more than 10 characters.'
            })

        # Return the validated values. This will be available as
        # the `.validated_data` property.
        return {
            'score': int(score),
            'player_name': player_name
        }

    def to_representation(self, obj):
        return {
            'score': obj.score,
            'player_name': obj.player_name
        }

    def create(self, validated_data):
        return HighScore.objects.create(**validated_data)
创建新的基类

BaseSerializer,如果你想实现新的通用串行类来处理特定的序列化的风格,或者使用可替换存储后端集成类也是有用的。

以下类是可以处理将任意对象强制为原始表示的通用序列化程序的示例。

class ObjectSerializer(serializers.BaseSerializer):
    """
    A read-only serializer that coerces arbitrary complex objects
    into primitive representations.
    """
    def to_representation(self, obj):
        for attribute_name in dir(obj):
            attribute = getattr(obj, attribute_name)
            if attribute_name('_'):
                # Ignore private attributes.
                pass
            elif hasattr(attribute, '__call__'):
                # Ignore methods and other callables.
                pass
            elif isinstance(attribute, (str, int, bool, float, type(None))):
                # Primitive types can be passed through unmodified.
                output[attribute_name] = attribute
            elif isinstance(attribute, list):
                # Recursively deal with items in lists.
                output[attribute_name] = [
                    self.to_representation(item) for item in attribute
                ]
            elif isinstance(attribute, dict):
                # Recursively deal with items in dictionaries.
                output[attribute_name] = {
                    str(key): self.to_representation(value)
                    for key, value in attribute.items()
                }
            else:
                # Force anything else to its string representation.
                output[attribute_name] = str(attribute)

高级串行器使用

重写序列化和反序列化行为

如果您需要更改串行化类的序列化,反序列化或验证,则可以通过覆盖.to_representation().to_internal_value()方法来实现。

这可能有用的一些原因包括...

  • 为新的序列化程序基类添加新行为。
  • 修改现有类的行为稍微。
  • 提高返回大量数据的经常访问的API端点的序列化性能。

这些方法的签名如下:

.to_representation(self, obj)

获取需要序列化的对象实例,并返回一个原始表示。通常这意味着返回一个内置的Python数据类型的结构。可以处理的确切类型将取决于您为API配置的渲染类。

.to_internal_value(self, data)

将未验证的传入数据作为输入,并返回将被提供的验证数据serializer.validated_data。如果在序列化器类上调用返回值也将被传递给.create().update()方法.save()

如果任何验证失败,那么该方法应该提出一个serializers.ValidationError(errors)。通常,errors这里的参数将是将字段名称映射到错误消息的字典。

data传递给此方法的参数通常是值request.data,因此它提供的数据类型将取决于您为API配置的解析器类。

串行器继承

与Django表单类似,您可以通过继承来扩展和重用序列化程序。这允许您在父类上声明一组通用的字段或方法,然后可以在多个序列化器中使用。例如,

class MyBaseSerializer(Serializer):
    my_field = serializers.CharField()

    def validate_my_field(self):
        ...

class MySerializer(MyBaseSerializer):
    ...

像Django ModelModelForm类一样,Meta序列化器上的内部类不会隐式继承自父Meta类的内部类。如果你希望Meta类从父类继承,你必须明确地这样做。例如:

class AccountSerializer(MyBaseSerializer):
    class Meta(MyBaseSerializer.Meta):
        model = Account

通常我们建议不要在内部Meta类上使用继承,而是明确声明所有选项。

另外,以下注意事项适用于序列化器继承:

  • 普通Python名称解析规则适用。如果您有多个基类声明一个Meta内部类,则只会使用第一个类。这意味着孩子Meta,如果存在,否则Meta第一个父母等等
  • Field通过将名称设置为子类,可以声明性地删除从父类继承None的类。

    class MyBaseSerializer(ModelSerializer):
        my_field = serializers.CharField()
    
    class MySerializer(MyBaseSerializer):
        my_field = None

    但是,您只能使用此技术从由父类声明性定义的字段中选择退出; 它不会阻止ModelSerializer生成默认字段。要从默认字段中选择退出,请参阅指定要包括哪些字段

动态修改字段

一旦串行器被初始化,可以使用.fields属性访问在串行器上设置的字段的字典。访问和修改此属性允许您动态地修改序列化程序。

fields直接修改参数允许您进行有趣的操作,例如在运行时更改序列化程序字段上的参数,而不是声明序列化程序。

例如,如果您希望能够设置序列化程序在初始化时使用哪些字段,则可以像这样创建一个序列化器类:

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)

这将允许您执行以下操作:

>>> class UserSerializer(DynamicFieldsModelSerializer):
>>>     class Meta:
>>>         model = User
>>>         fields = ('id', 'username', 'email')
>>>
>>> print UserSerializer(user)
{'id': 2, 'username': 'jonwatts', 'email': 'jon@example.com'}
>>>
>>> print UserSerializer(user, fields=('id', 'email'))
{'id': 2, 'email': 'jon@example.com'}

自定义默认字段

REST框架2提供了一个API,允许开发人员覆盖ModelSerializer类如何自动生成默认字段集。

该API包括.get_field().get_pk_field()和其他方法。

因为序列化程序已经从根本上重新设计为3.0,这个API不再存在。您仍然可以修改创建的字段,但需要引用源代码,并且请注意,如果您所做的更改与API的私有位置相关,则可能会发生更改。


第三方包

以下第三方软件包也可用。

Django REST棉花糖

django的静止-棉花糖软件包提供了序列化器的替换实现中,使用Python棉花糖库。它暴露与REST框架序列化程序相同的API,并且可以在某些用例中用作替换。

Serpy

serpy包是是为速度而序列化的另一种实现。Serpy将复杂数据类型序列化为简单的本机类型。原生类型可以轻松转换为JSON或任何其他格式。

MongoengineModelSerializer

django的静止框架-mongoengine包提供了一个MongoEngineModelSerializer支持使用的MongoDB作为Django的REST框架存储层串行器类。

GeoFeatureModelSerializer

The django-rest-framework-gis package provides a GeoFeatureModelSerializer serializer class that supports GeoJSON both for read and write operations.

HStoreSerializer

The django-rest-framework-hstore package provides an HStoreSerializer to supportdjango-hstoreDictionaryField model field and its schema-mode feature.

Dynamic REST

The dynamic-rest package extends the ModelSerializer and ModelViewSet interfaces, adding API query parameters for filtering, sorting, and including / excluding all fields and relationships defined by your serializers.

Dynamic Fields Mixin

The drf-dynamic-fields package provides a mixin to dynamically limit the fields per serializer to a subset specified by an URL parameter.

DRF FlexFields

The drf-flex-fields package extends the ModelSerializer and ModelViewSet to provide commonly used functionality for dynamically setting fields and expanding primitive fields to nested models, both from URL parameters and your serializer class definitions.

Serializer Extensions

The django-rest-framework-serializer-extensionspackage provides a collection of tools to DRY up your serializers, by allowingfields to be defined on a per-view/request basis. Fields can be whitelisted,blacklisted and child serializers can be optionally expanded.

HTML JSON Forms

The html-json-forms package provides an algorithm and serializer for processing<form> submissions per the (inactive) HTML JSON Form specification. The serializer facilitates processing of arbitrarily nested JSON structures within HTML. For example,<input name="items[0][id]" value="5"> will be interpreted as {"items": [{"id": "5"}]}.

DRF-Base64

DRF-Base64 provides a set of field and model serializers that handles the upload of base64-encoded files.

QueryFields

djangorestframework-queryfields allows API clients to specify which fields will be sent in the response via inclusion/exclusion query parameters.

DRF Writable Nested

The drf-writable-nested package provides writable nested model serializer which allows to create/update models with nested related data.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值