【djangorestframework】6、Serializers-ModelSerializer(序列化器)

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(Inspecting a ModelSerializer)

  • 序列化器类生成有用的详细表示字符串,允许你全面检查其字段的状态。在使用ModelSerializer时特别有用,因为你想确定为你自动创建了哪些字段和验证器。
  • 为此,使用python manage.py shell 打开Django 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())

指定要包含的字段(Specifying which fields to include)

  • 如果你只想在模型序列化器中使用默认字段的子集,则可以使用fields或exclude选项,就像使用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_name和created会被序列化。
  • 在fields和exclude属性中的名称,通常会映射到模型类中的模型字段。或者,fields选项中的名称可以映射到不包含模型类中存在的参数的属性或方法
  • 从版本3.3.0开始,必须提供其中一个属性fields或exclude

指定嵌套序列化(Specifying nested serialization)

  • 默认的ModelSerializer使用主键进行关联,但你也可以使用depth选项轻松的生成嵌套关联
class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')
        depth = 1
  • depth选项应设置为一个整数值,该值指示在恢复为平面表示之前应该遍历的关系深度。(后半句没看懂)
  • 如果要自定义序列化的方式,则需要自己定义字段

显式指定字段(Specifying fields explicitly)

  • 你可以向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
  • 额外的字段可以对应模型上任何属性或可调用的(字段)

指定只读字段(Specifying read only fields)

  • 你可能希望将多个字段指定为只读。你可以使用快捷的Meta选项read_only_fields,而不是使用read_only=True属性显式的添加每个字段。
  • 该选项应该是字段名称的列表或元祖,并声明如下:
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=True和default=...关键字参数。
  • 其中一个例子是与当前已认证User的只读关系,它与另一个标识符是unique_together。在这种情况下,你可以声明用户字段,如下所示:
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
  • 有关UniqueTogetherValidator和CurrentUserDefault类的详细文档,请查阅验证器文档。

附加关键字参数(Additional keyword arguments)

  • 还有一个快捷方式允许你使用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

关系字段(Relational fields)

  • 序列化模型实例时,你可以选择多种不同的方式来表示关联关系。ModelSerializer的默认表示是使用相关实例的主键。
  • 替代表示方式包括使用超链接序列化,序列化完整的嵌套表示或者使用自定义表示的序列化。
  • 有关详细信息,请查阅序列化器关系文档。

自定义字段映射(Customizing field mappings)

  • ModelSerializer类还公开了一个可以重写的API,以便在实例化序列化器时更改如何自动确定序列化器字段。
  • 通常,如果ModelSerializer默认情况下没有生成你需要的字段,那么你应该将它们显式地添加到类中,或者简单地使用常规的Serializer类。但是在某些情况下,你可能需要创建一个新的基类,来定义如何为任意给定模型创建序列化字段。
  • .serializer_field_mapping
    • Django模型类到REST framework序列化器类的映射。你可以重写此映射以更改应该用于每个模型类的默认序列化器类。
  • .serializer_related_field
    • 此属性应是序列化器字段类。默认情况下用于关联字段。
  • 对于ModelSerializer此属性默认是PrimaryKeyRelatedField
  • 对于HyperlinkedModelSerializer此属性默认是serializers.HyperlinkedRelatedField.
  • serializer_url_field
    • 应该用于序列化器上任何url字段的序列化器字段类。
    • 默认是serializers.HyperlinkedIdentityField
  • serializer_choice_field
    • 应用于序列化器上任何选择字段的序列化器字段类。
    • 默认是serializers.ChoiceField

The field_class 和 field_kwargs API

  • 调用下面的方法来确定应该自动包含在序列化器中每个字段的类和关键字参数。这些方法都应该返回(field_class, field_kwargs)元祖。
  • 调用以生成映射到标准模型字段的序列化器字段
  • 默认实现返回基于serializer_field_mapping属性的序列化器类。
  • .build_relational_field(self, field_name, relation_info)
    • 调用以生成映射到关系模型字段的序列化器字段。
    • 默认实现返回基于serializer_relational_field属性的序列化器类。
    • relation_info参数是一个命名元祖,包含model_field, related_model,to_many和has_through_model属性
  • .build_nested_field(self, field_name, relation_info, nested_depth)
    • 当设置了depth选项时,调用以生成映射到关系模型字段的序列化器字段。
    • 默认实现基于ModelSerializer或HyperlinkedModelSerializer动态创建嵌套的序列化器类。
    • nested_depth的值是depth选项的值减1
    • relation_info参数是衣个命名元祖,包含model_field,related_model,to_many和has_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)
    • 当字段名称未映射到任何模型字段或模型属性时调用。默认实现会引发错误,但子类可以自定义此行为
posted @ 2022-04-25 15:58  郭祺迦  阅读(360)  评论(0)    收藏  举报