当前位置: 首页 > 工具软件 > REST Superman > 使用案例 >

Serializers - Django REST framework

能向晨
2023-12-01

序列化器-Django REST框架

serializers.py

串行化

扩展序列化程序的有用性是我们想要解决的问题。然而,这不是一个微不足道的问题,它将需要一些认真的设计工作。

拉塞尔·基思-马吉Django用户组

序列化器允许将复杂数据(如queryset和模型实例)转换为本机Python数据类型,然后这些数据类型可以很容易地呈现到JSON, XML或其他内容类型。序列化程序还提供反序列化,允许在首先验证传入数据之后将解析的数据转换回复杂的类型。

REST框架中的序列化程序的工作方式非常类似Django的FormModelForm上课。我们提供Serializer类,它为您提供了一种强大的、通用的方法来控制响应的输出,以及模型串列器类,它为创建处理模型实例和查询集的序列化程序提供了有用的快捷方式。

声明序列化器

让我们首先创建一个简单的对象,例如,我们可以使用:

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本地数据类型..。

import io
from rest_framework.parsers import JSONParser

stream = io.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直接财产。

验证

当反序列化数据时,始终需要调用is_valid()在尝试访问已验证的数据或保存对象实例之前。如果出现任何验证错误,则.errors属性将包含表示结果错误消息的字典。例如:

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.']}

字典中的每个键都是字段名,值将是与该字段对应的任何错误消息的字符串列表。这个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>方法应该返回已验证的值或引发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子类。此方法只使用一个参数,即字段值字典。它应该引起一个serializers.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 start is before finish.
        """
        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']
        )

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

访问初始数据和实例

当将初始对象或queryset传递给序列化程序实例时,该对象将作为.instance...如果没有传递初始对象,则.instance属性将是None.

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

部分更新

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

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': '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': ['Enter a valid e-mail address.']}, 'created': ['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要求您始终显式地编写这些方法。默认模型串列器 .create().update()方法不包括对可写嵌套表示的支持。

然而,也有一些第三方包可用,例如DRF可写嵌套支持自动可写嵌套表示。

处理模型管理器类中的相关实例

在序列化程序中保存多个相关实例的一个替代方法是编写处理创建正确实例的自定义模型管理器类。

例如,假设我们希望确保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()现在可以重写序列化程序类上的方法,以使用新的管理器方法。

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

有关此方法的更多详细信息,请参见模型经理,和这篇关于使用模型和管理类的博文.

处理多个对象

这个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'}
# ]

反序列化多个对象

反序列化多个对象的默认行为是支持多个对象创建,但不支持多个对象更新。有关如何支持或自定义这些情况之一的详细信息,请参阅李斯特均衡器下文文件。

包括额外的上下文

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

您可以通过传递context实例化序列化程序时的参数。例如:

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

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


模型串列器

通常,您需要与Django模型定义紧密映射的序列化程序类。

这个模型串列器类提供一个快捷方式,使您能够自动创建Serializer使用与模型字段对应的字段初始化。

这个模型串列器类与普通类相同。Serializer类,除了:

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

宣告模型串列器看起来是这样的:

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

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

模型上的任何关系(例如外键)都将映射到PrimaryKeyRelatedField...默认情况下不包括反向关系,除非显式地包括在串行化关系文件。

检查模型串列器

序列化器类生成有用的详细表示字符串,使您能够全面检查其字段的状态。这在使用ModelSerializers您想要确定哪些字段和验证器是自动为您创建的。

为此,打开Django shell,使用python manage.py shell,然后导入序列化程序类,实例化它,并打印对象表示形式…。

>>> 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模型有三个字段account_name, users,和created,这将导致字段account_namecreated被序列化。

的名字fieldsexclude属性通常将映射到模型类上的模型字段。

fields选项可以映射到不接受模型类中存在的参数的属性或方法。

从3.3.0版本开始,它是强制性若要提供下列属性之一,请执行以下操作fieldsexclude.

指定嵌套序列化

默认模型串列器为关系使用主键,但也可以使用depth备选方案:

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

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

如果要自定义序列化的完成方式,则需要自己定义字段。

显式指定字段

可以将额外的字段添加到模型串列器或者通过声明类上的字段来覆盖默认字段,就像对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=…关键字参数。

其中一个示例是当前身份验证的只读关系。User那就是unique_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

请记住,如果字段已在序列化程序类上显式声明,则extra_kwargs选项将被忽略。

关系字段

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

其他表示形式包括使用超链接进行序列化、序列化完整的嵌套表示形式或使用自定义表示形式进行序列化。

有关详细信息,请参阅串行化关系文件。

自定义字段映射

ModelSeriizer类还公开了一个API,您可以重写该API,以更改在实例化序列化程序时如何自动确定序列化程序字段。

通常情况下,如果模型串列器默认情况下不生成您需要的字段,那么您应该显式地将它们添加到类中,或者只使用常规字段。Serializer而是上课。但是,在某些情况下,您可能希望创建一个新的基类,它定义了如何为任何给定模型创建序列化器字段。

.serializer_field_mapping

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

.serializer_related_field

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

模型串列器这默认为PrimaryKeyRelatedField.

超链接模型序列化器这默认为serializers.HyperlinkedRelatedField.

serializer_url_field

应该用于任何url字段在序列化程序上。

默认为serializers.HyperlinkedIdentityField

serializer_choice_field

序列化程序字段类,应用于序列化程序上的任何选择字段。

默认为serializers.ChoiceField

字段类和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_related_field属性。

这个relation_info参数是一个名为tuple的参数,它包含model_field, related_model, to_manyhas_through_model财产。

.build_nested_field(self, field_name, relation_info, nested_depth)

调用以生成映射到关系模型字段的序列化器字段,当depth选项已经设置。

默认实现基于以下任意一个动态创建嵌套序列化器类模型串列器超链接模型序列化器.

这个nested_depth的值。depth选项,减一。

这个relation_info参数是一个名为tuple的参数,它包含model_field, related_model, to_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)

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


超链接模型序列化器

这个超链接模型序列化器类类似于模型串列器类,但它使用超链接来表示关系,而不是主键。

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

url字段将使用HyperlinkedIdentityField序列化器字段,模型上的任何关系都将使用HyperlinkedRelatedField串行化字段

通过将主键添加到fields例如,选项:

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

绝对和相对网址

实例化超链接模型序列化器必须包括当前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一种超链接模型序列化器实例是一种非常有用的方法,可以准确地检查关系应该映射的视图名称和查找字段。


更改URL字段名

URL字段的名称默认为“url”。可以全局重写此操作,方法是使用URL_FIELD_NAME背景。


李斯特均衡器

这个李斯特均衡器类提供一次序列化和验证多个对象的行为。你不会典型需要使用李斯特均衡器直接,但应该直接通过many=True实例化序列化程序时。

当序列化程序被实例化并且many=True已通过,李斯特均衡器实例将被创建。序列化程序类然后成为父类的子类。李斯特均衡器

下面的参数也可以传递给李斯特均衡器字段或传递的序列化程序。many=True:

allow_empty

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

定制化李斯特均衡器行为

那里当您想要自定义李斯特均衡器行为。例如:

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

对于这些情况,您可以在many=True通过使用list_serializer_class选项在序列化程序上。Meta班级,等级。

例如:

class CustomListSerializer(serializers.ListSerializer):
    ...

class CustomSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = CustomListSerializer

自定义多个创建

创建多个对象的默认实现是简单地调用.create()对于列表中的每个项目。如果要自定义此行为,则需要自定义.create()方法上李斯特均衡器类时使用的many=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

自定义多个更新

默认情况下,李斯特均衡器类不支持多个更新。这是因为插入和删除应该期望的行为是不明确的。

要支持多个更新,您需要显式地这样做。在编写多个更新代码时,请确保记住以下几点:

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

您将需要添加一个显式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()
    ...

    class Meta:
        list_serializer_class = BookListSerializer

可以将第三方包与3.1版本一起包含,该版本为多个更新操作提供了一些自动支持,类似于allow_add_removeREST框架2中存在的行为。

自定义ListSeriizer初始化

当序列化程序具有many=True实例化后,我们需要确定哪些参数和关键字参数应该传递给.__init__()方法都适用于两个孩子。Serializer类,以及父类的李斯特均衡器班级,等级。

默认实现是将所有参数传递给两个类,但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)

基串联器

基串联器类,可用于轻松支持其他序列化和反序列化样式。

类实现的基本API与Serializer班级:

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

可以重写四种方法,具体取决于您希望序列化程序类支持的功能:

  • .to_representation()-重写此操作以支持序列化,用于读取操作。
  • .to_internal_value()-重写此操作以支持反序列化操作。
  • .create().update()-覆盖这两种方法中的一种或两种,以支持保存实例。

因为该类提供的接口与Serializer类时,您可以将它与现有的基于泛型类的视图一起使用,就像对常规视图一样。Serializer模型串列器.

当您这样做时,您会注意到的唯一不同是基串联器类不会在可浏览API中生成HTML表单。这是因为它们返回的数据不包括允许将每个字段呈现到适当的HTML输入中的所有字段信息。

只读基串联器

若要实现只读序列化程序,请使用基串联器类,我们只需重写.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)
读写基串联器

要创建读写序列化程序,我们首先需要实现.to_internal_value()方法。此方法返回将用于构造对象实例的验证值,并可能引发serializers.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 serializers.ValidationError({
                'score': 'This field is required.'
            })
        if not player_name:
            raise serializers.ValidationError({
                'player_name': 'This field is required.'
            })
        if len(player_name) > 10:
            raise serializers.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)

创建新基类

这个基串联器类也很有用,如果您希望实现新的泛型序列化器类,以处理特定的序列化样式,或与其他存储后端集成。

下面的类是一个泛型序列化程序的示例,它可以处理将任意对象强制生成基本表示形式的问题。

class ObjectSerializer(serializers.BaseSerializer):
    """
    A read-only serializer that coerces arbitrary complex objects
    into primitive representations.
    """
    def to_representation(self, obj):
        output = {}
        for attribute_name in dir(obj):
            attribute = getattr(obj, attribute_name)
            if attribute_name.startswith('_'):
                # 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)
        return output

高级序列化器使用

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

如果需要更改序列化程序类的序列化或反序列化行为,则可以通过重写.to_representation().to_internal_value()方法。

一些可能有用的理由包括..。

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

这些方法的签名如下:

.to_representation(self, obj)

获取需要序列化的对象实例,并应返回基本表示形式。通常,这意味着返回内置Python数据类型的结构。可以处理的确切类型将取决于为API配置的呈现类。

可能会被重写以修改表示样式。例如:

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)

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

如果任何验证失败,则该方法应引发serializers.ValidationError(errors)...这个errors参数应该是映射字段名的字典(或settings.NON_FIELD_ERRORS_KEY)到错误消息列表。如果您不需要更改反序列化行为,而是希望提供对象级别的验证,则建议您重写.validate()方法。

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

串行化继承

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

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

    def validate_my_field(self, value):
        ...

class MySerializer(MyBaseSerializer):
    ...

像Django‘sModelModelForm类,内在Meta类不会隐式地从父类的内部继承Meta上课。如果你想Meta类继承父类,必须显式地这样做。例如:

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

通常我们会建议在内部元类上使用继承,而是显式声明所有选项。

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

  • 适用一般的Python名称解析规则。如果有多个基类声明Meta内部类,只使用第一个类。这意味着孩子的Meta,如果存在,则为Meta第一家长等。

  • 可以声明地删除Field通过将名称设置为None在子类上。

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

    但是,您只能使用此技术从父类以声明方式定义的字段中选择退出;它不会阻止模型串列器生成默认字段。若要从默认字段中选择退出,请参见指定要包括哪些字段.

动态修改字段

初始化序列化程序后,可以使用.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)
            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,允许开发人员覆盖模型串列器类将自动生成默认字段集。

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

因为序列化器已经从根本上用3.0重新设计了,这个API就不再存在了。您仍然可以修改创建的字段,但是您需要参考源代码,并且要注意,如果您所做的更改是针对API的私有部分的,那么它们可能会发生更改。


第三方包

下面的第三方包也是可用的。

Django休息棉花糖

这个Django-休息-棉花糖包为序列化程序提供了另一种实现,使用python棉花糖图书馆。它公开了与REST框架序列化器相同的API,并可在某些用例中用作插入替换。

塞比

这个锯齿状包是为速度而构建的序列化程序的替代实现。塞比将复杂数据类型序列化为简单的本机类型。本机类型可以很容易地转换为JSON或任何其他所需的格式。

MongoEngineer模型序列化器

这个Django-REST框架-MongoEngine包提供了一个MongoEngineModelSerializer序列化类,它支持使用MongoDB作为Django REST框架的存储层。

GeoFeatureModel串联器

这个Django-REST框架-gis包提供了一个GeoFeatureModel串联器序列化类,它支持GeoJSON的读写操作。

HStoreSeriizer

这个Django-REST框架-hStore包提供了一个HStoreSeriizer支持Django-hStore DictionaryField模型场及其schema-mode特征。

动态休息

这个动态休息包扩展了ModelSeriizer和ModelViewSet接口,添加了用于筛选、排序以及包括/排除序列化器定义的所有字段和关系的API查询参数。

动态场

这个动态场包提供了一个混合体,以动态地将每个序列化程序的字段限制为由URL参数指定的子集。

DRF Flexfield

这个DRF-FLEX场包扩展了ModelSeriizer和ModelViewSet,以提供用于动态设置字段和将原始字段扩展到嵌套模型的常用功能,包括URL参数和序列化程序类定义。

串行化扩展

这个Django-REST-框架-序列化器-扩展包提供了一组工具,通过允许在每个视图/请求的基础上定义字段,从而使序列化程序干涸。字段可以被白名单,黑名单和子序列化可以有选择地展开。

HTMLJSON表单

这个HTML-json-窗体包提供了用于处理的算法和序列化程序。<form>提交(不活动)HTMLJSON表单规范...序列化程序便于处理HTML中任意嵌套的JSON结构。例如,<input name="items[0][id]" value="5">将被解释为{"items": [{"id": "5"}]}.

DRF-BASE 64

DRF-BASE 64提供一组字段和模型序列化程序,这些序列化程序处理Base 64编码文件的上载。

奎尔菲尔德

djangorestframework-queryfield允许API客户端通过包含/排除查询参数指定将在响应中发送哪些字段。

DRF可写嵌套

这个可写嵌套包提供可写嵌套模型序列化程序,允许使用嵌套相关数据创建/更新模型。

 类似资料:

相关阅读

相关文章

相关问答