DRF-序列化器

Serializer序列化

声明序列化器

声明一个序列化器看起来非常类似于声明一个表单:

from rest_framework import serializers

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

保存实例

如果我们希望能够基于经过验证的数据返回完整的对象实例,我们需要实现一个或两个.create()and.update()方法。例如:

classCommentSerializer(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)
        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(). 例如:

serializer.save(owner=request.user)

验证

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

字段级验证

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

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

您的validate_<field_name>方法应该返回经过验证的值或引发serializers.ValidationError. 例如:

from rest_framework import serializers

classBlogPostSerializer(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'notin value.lower():
            raise serializers.ValidationError("Blog post is not about Django")
        return value

注意: 如果您<field_name>在序列化程序上声明了参数,required=False则如果不包含该字段,则不会执行此验证步骤。


对象级验证

要执行需要访问多个字段的任何其他验证,请添加一个调用.validate()到您的Serializer子类的方法。此方法采用单个参数,即字段值字典。serializers.ValidationError如有必要,它应该引发 a ,或者只返回经过验证的值。例如:

from rest_framework import serializers

classEventSerializer(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')

classGameRecord(serializers.Serializer):
    score =IntegerField(validators=[multiple_of_ten])
    ...

序列化程序类还可以包括应用于完整字段数据集的可重用验证器。这些验证器通过在内部Meta类中声明它们来包含,如下所示:

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

    classMeta:
        # 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':'foo bar'},partial=True)

处理嵌套对象

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

该类Serializer本身是 的一种类型Field,可用于表示一个对象类型嵌套在另一个对象类型中的关系。

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

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

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

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

同样,如果嵌套表示应该是项目列表,则应将many=True标志传递给嵌套序列化程序。

classCommentSerializer(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()处理保存多个对象的方法。

以下示例演示了如何使用嵌套的配置文件对象创建用户。

classUserSerializer(serializers.ModelSerializer):
    profile =ProfileSerializer()

    classMeta:
        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 following 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 framework 3 要求您始终明确地编写这些方法。默认值ModelSerializer .create().update()方法不包括对可写嵌套表示的支持。

但是,有第三方包可用,例如支持自动可写嵌套表示的DRF Writable Nested 。

ModelSerializer模型序列化器

ModelSerializer类与普通Serializer课程相同,除了

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

声明 aModelSerializer看起来像这样:

classAccountSerializer(serializers.ModelSerializer):
    classMeta:
        model =Account
        fields =['id','account_name','users','created']
指定包含字段

如果您只想在模型序列化程序中使用默认字段的子集,则可以使用fieldsorexclude选项来实现

从 3.3.0 版开始,必须提供属性之一fieldsexclude.

字段扩展与重写

通过在类上声明字段来向 a 添加额外字段ModelSerializer或覆盖默认字段

指定只读字段

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

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

附加关键字参数

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

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

classCreateUserSerializer(serializers.ModelSerializer):
    classMeta:
        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选项将被忽略。

序列化器字段

read_only

只读字段包含在 API 输出中,但不应包含在创建或更新操作期间的输入中。任何错误地包含在序列化程序输入中的“read_only”字段都将被忽略。

设置此项以True确保在序列化表示时使用该字段,但在反序列化期间创建或更新实例时不使用该字段。

默认为False

write_only

设置此项以True确保在更新或创建实例时可以使用该字段,但在序列化表示时不包括在内。

默认为False

required

如果在反序列化期间未提供字段,通常会引发错误。如果在反序列化期间不需要此字段,则设置为 false。

将此设置为False还允许在序列化实例时从输出中省略对象属性或字典键。如果密钥不存在,它将根本不包含在输出表示中。

默认为True. 如果您使用模型序列化程序,默认值将是False如果您在.blank=True``default``null=True``Model

default

如果设置,如果没有提供输入值,这将给出将用于该字段的默认值。如果未设置,则默认行为是根本不填充属性。

default部分更新操作期间不应用。在部分更新的情况下,只有传入数据中提供的字段才会返回经过验证的值。

可以设置为函数或其他可调用对象,在这种情况下,每次使用时都会评估该值。调用时,它将不接收任何参数。如果可调用对象具有requires_context = True属性,则序列化器字段将作为参数传递。

例如:

classCurrentUserDefault:
    """
    May be applied as a `default=...` value on a serializer field.
    Returns the current user.
    """
    requires_context =True

    def __call__(self, serializer_field):
        return serializer_field.context['request'].user

序列化实例时,如果实例中不存在对象属性或字典键,则将使用默认值。

请注意,设置一个default值意味着该字段不是必需的。同时包含 thedefaultrequired关键字参数是无效的,并且会引发错误。

allow_null

None如果传递给序列化器字段,通常会引发错误。将此关键字参数设置为TrueifNone应被视为有效值。

请注意,如果没有明确的default,将此参数设置为True将意味着序列化输出的defaultnull,但并不意味着输入反序列化的默认值。

默认为False

验证器

当前用户默认值

可用于表示当前用户的默认类。为了使用它,必须在实例化序列化程序时将“请求”作为上下文字典的一部分提供。

owner = serializers.HiddenField(
    default=serializers.CurrentUserDefault()
)
CreateOnlyDefault

一个默认类,可用于 在创建操作期间仅设置默认参数 。在更新期间,该字段被省略。

它接受一个参数,这是在创建操作期间应使用的默认值或可调用对象。

created_at = serializers.DateTimeField(
    default=serializers.CreateOnlyDefault(timezone.now)
)
唯一验证器

此验证器可用于unique=True对模型字段实施约束。它需要一个必需参数和一个可选messages参数:

  • queryset required - 这是应该强制执行唯一性的查询集。
  • message- 验证失败时应使用的错误消息。
  • lookup- 用于查找具有正在验证的值的现有实例的查找。默认为'exact'.

此验证器应应用于 序列化器字段 ,如下所示:

from rest_framework.validators importUniqueValidator

slug =SlugField(
    max_length=100,
    validators=[UniqueValidator(queryset=BlogPost.objects.all())]
)
UniqueTogetherValidator

此验证器可用于unique_together对模型实例实施约束。它有两个必需参数和一个可选messages参数:

  • queryset required - 这是应该强制执行唯一性的查询集。
  • fields required - 字段名称的列表或元组,应构成唯一集。这些必须作为序列化程序类的字段存在。
  • message- 验证失败时应使用的错误消息。

验证器应应用于 序列化程序类 ,如下所示:

from rest_framework.validators importUniqueTogetherValidator

classExampleSerializer(serializers.Serializer):
    # ...
    classMeta:
        # ToDo items belong to a parent list, and have an ordering defined
        # by the 'position' field. No two items in a given list may share
        # the same position.
        validators =[
            UniqueTogetherValidator(
                queryset=ToDoItem.objects.all(),
                fields=['list','position']
            )
        ]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值