Django REST Framework的数据类序列化器(在合并PR之前暂时使用)
项目描述
为数据类提供Django REST Framework的序列化器。
要求
Python (3.7+)
Django (2.0+)
Django REST Framework (3.9+)
这些是支持的Python和包版本。旧版本也可能同样适用,但作者尚未测试。
安装
$ pip install djangorestframework-dataclasses
此包遵循语义版本控制。有关重大变更和新功能,请参阅变更日志,有关完整的许可协议(BSD-3-clause),请参阅许可协议。
基本用法
该包提供了在rest_framework_dataclasses.serializers命名空间中定义的DataclassSerializer序列化器。
from rest_framework_dataclasses.serializers import DataclassSerializer
本序列化器提供了一个快捷方式,允许您自动创建一个与数据类字段对应的 Serializer 类。在用法上,DataclassSerializer 与常规 Serializer 类相同,但除了
它将自动为您生成字段,基于数据类的声明。
为了实现这一点,它需要在 Meta 子类中指定一个 dataclass 属性,其值为具有类型注解的数据类。
它包括 .create() 和 .update() 的默认实现。
例如,定义一个数据类如下
@dataclass
class Person:
name: str
email: str
alive: bool
gender: typing.Literal['male', 'female']
birth_date: typing.Optional[datetime.date]
phone: typing.List[str]
movie_ratings: typing.Dict[str, int]
现在可以为这个数据类轻松地定义序列化器,无需复制所有字段
class PersonSerializer(DataclassSerializer):
class Meta:
dataclass = Person
# is equivalent to
class PersonSerializer(Serializer):
name = fields.CharField()
email = fields.CharField()
alive = fields.BooleanField()
gender = fields.ChoiceField(choices=['male', 'female'])
birth_date = fields.DateField(allow_null=True)
phone = fields.ListField(child=fields.CharField())
movie_ratings = fields.DictField(child=fields.IntegerField())
您可以通过在类上显式声明来添加额外字段或覆盖默认字段,就像为常规 Serializer 类做的那样。这允许指定额外的字段选项或更改字段类型。
class PersonSerializer(Serializer):
email = fields.EmailField()
class Meta:
dataclass = Person
数据类序列化器的行为与内置的 Django REST Framework 序列化器相同,可以在相同的位置使用:您可以使用 .data 属性检索序列化表示,使用 .validated_data 属性检索反序列化的数据类实例。此外,实现了 save() 方法来创建或更新现有的数据类实例。有关序列化器的更多信息,请参阅 Django REST Framework 文档。
请注意,此用法模式与内置的 ModelSerializer 非常相似。这是故意的,整个 API 都是按照 ModelSerializer 的模型设计的。大多数从 ModelSerializer 知道的特性和行为也适用于数据类序列化器。
自定义字段生成
自动生成的序列化器字段是根据数据类中的类型限定符配置的(这些可以是混合的)
具有默认值(工厂)的字段在序列化器上标记为可选(required=False)。这意味着这些字段在反序列化期间不需要提供。
通过 typing.Optional 或 typing.Union[X, None] 标记为可空的字段在序列化器上标记为可空(allow_null=True)。这意味着在反序列化期间接受 None 作为有效值。
通过 typing.Final 标记为最终的字段(如 PEP 591 中所述)在序列化器上标记为只读(read_only=True)。
@dataclass
class Person:
birth_date: typing.Optional[datetime.date]
alive: bool = True
species: typing.Final[str] = 'Human'
# the autogenerated serializer will be equal to
class PersonSerializer(Serializer):
birth_date = fields.DateField(allow_null=True)
alive = fields.BooleanField(required=False)
species = fields.CharField(read_only=True)
除了在序列化器上显式声明来覆盖字段外,您还可以使用数据类字段的元数据来更改或覆盖生成的序列化器字段。目前,此字典中识别了两个键
serializer_field 可用于用用户提供的字段替换自动生成的字段。应包含字段的实例,而不是字段类型。
serializer_kwargs 可用于为生成的字段指定任意额外的关键字参数。手动指定的参数将优先于生成的参数(例如,通过提供 {required: True},可以将具有默认值的字段变为必填)。
@dataclasses.dataclass
class Person:
email: str = dataclasses.field(metadata={'serializer_field': fields.EmailField()})
age: int = dataclasses.field(metadata={'serializer_kwargs': {'min_value': 0}})
# the autogenerated serializer will be equal to
class PersonSerializer(Serializer):
email = fields.EmailField()
age = fields.IntegerField(min_value=0)
为了进一步自定义序列化器,DataclassSerializer 接受 Meta 子类中的以下选项。所有选项的行为与 ModelSerializer 中相同。
dataclass 指定序列化器使用的数据类类型。这相当于 ModelSerializer 中的 model 选项。
fields 和 exclude 可以用来指定序列化器中分别应包含和排除的字段。这两个选项不能同时指定。
fields 选项接受魔法值 __all__,以指定在数据类上使用所有字段。这也是默认值,因此不需要指定 fields 或 exclude。
read_only_fields 可以用来标记一组字段为只读。
extra_kwargs 可以用来指定字段上的任意额外关键字参数。这可以在不显式声明字段的情况下扩展或更改自动生成的字段。此选项应是一个字典,将字段名称映射到关键字参数的字典。
如果自动生成的字段是复合字段(列表或字典),则这些参数应用于复合字段。要向复合字段的子字段(即列表或字典中的项所用的字段)添加关键字参数,它们应指定为 child_kwargs 名称下的嵌套字典(有关示例,请参阅下文 嵌套数据类 部分)。
class PersonSerializer(DataclassSerializer): class Meta: extra_kwargs = { 'height': { 'decimal_places': 1 }, 'movie_ratings': { 'child_kwargs': { 'min_value': 0, 'max_value': 10 } } }
validators 功能保持不变。
depth(如 ModelSerializer 中所知)不受支持,它将无限递归嵌套。
嵌套
嵌套数据类
如果您的数据类字段包含数据类实例,DataclassSerializer 将自动为该字段创建另一个 DataclassSerializer,以便其值嵌套。这也适用于包含在列表或字典中的数据类,甚至是多层嵌套。
@dataclass
class House:
address: str
owner: Person
residents: typing.List[Person]
class HouseSerializer(DataclassSerializer):
class Meta:
dataclass = House
这将序列化为
>>> serializer = HouseSerializer(instance=house)
>>> serializer.data
{
'address': 'Main Street 5',
'owner': { 'name': 'Alice' }
'residents': [
{ 'name': 'Alice', 'email': 'alice@example.org', ... },
{ 'name': 'Bob', 'email': 'bob@example.org', ... },
{ 'name': 'Charles', 'email': 'charles@example.org', ... }
]
}
这不会提供自定义嵌套数据类字段生成的功能。如果需要,应显式声明用于嵌套字段的序列化器。或者,可以使用 extra_kwargs 选项为属于嵌套数据类的字段提供参数。考虑以下
@dataclass
class Transaction:
amount: Decimal
account_number: str
@dataclass
class Company:
sales: List[Transaction]
为了告诉 DRF 为交易账户号提供 2 位小数,请将序列化器编写如下
class CompanySerializer(DataclassSerializer):
class Meta:
dataclass = Company
extra_kwargs = {
'sales': {
# Arguments here are for the ListField generated for the sales field on Company
'min_length': 1, # requires at least 1 item to be present in the sales list
'child_kwargs': {
# Arguments here are passed to the DataclassSerializer for the Transaction dataclass
'extra_kwargs': {
# Arguments here are the extra arguments for the fields in the Transaction dataclass
'amount': {
'max_digits': 6,
'decimal_places': 2
}
}
}
}
}
嵌套模型
同样,如果您的数据类字段包含 Django 模型,DataclassSerializer 将自动为您生成关系字段。
class Company(models.Model):
name = models.CharField()
@dataclass
class Person:
name: str
employer: Company
这将序列化为
>>> serializer = PersonSerializer(instance=user)
>>> print(repr(serializer))
PersonSerializer():
name = fields.CharField()
employer = fields.PrimaryKeyRelatedField(queryset=Company.objects.all())
>>> serializer.data
{
"name": "Alice",
"employer": 1
}
如果您想在序列化表示中嵌套模型,应通过显式声明字段来指定要使用的模型序列化器。
如果您更喜欢使用超链接而不是主键来表示关系,在同一个包中可以找到 HyperlinkedDataclassSerializer 类:它生成 HyperlinkedRelatedField 而不是 PrimaryKeyRelatedField。
新的序列化器字段类型
为了处理 DRF 未提供的序列化器字段的一些类型,rest_framework_dataclasses.fields 命名空间中提供了一些新的序列化器字段类型。这些字段可以独立于 DataclassSerializer 使用。
DefaultDecimalField
DecimalField 的子类,默认 max_digits 为 None 和 decimal_places 为 2。用于表示没有显式配置字段的十进制值。
EnumField
ChoiceField 的子类,用于表示 Python 枚举。枚举成员可以用其名称或值表示。成员名称用作显示名称。
签名: EnumField(enum_class, by_name=False)
enum_class: 枚举类。
by_name: 成员是否以它们的值(False)或名称(True)表示。
高级用法
通过将方法或属性名称添加到 Meta 类中的 fields 选项,可以将数据类上方法或属性的输出包含为序列化状态中的一个(只读)字段。
如果您不需要自定义生成的字段,可以直接使用 DataclassSerializer 而不是创建子类。在这种情况下,应使用 dataclass 构造函数参数指定数据类。
serializer = DataclassSerializer(data=request.data, dataclass=Person)
通过将 partial 参数设置为 True 支持部分更新。嵌套数据类也将被部分更新,但嵌套字段和字典将完全用提供值替换。
@dataclass class Company: name: str location: Optional[str] = None @dataclass class Person: name: str current_employer: Company past_employers: List[Company] alice = Person(name='Alice', current_employer=Company('Acme Corp.', 'New York City'), past_employers=[Company('PSF', 'Delaware'), Company('Ministry of Silly Walks', 'London')]) data = {'current_employer': {'location': 'Los Angeles'}, 'past_employers': [{'name': 'OsCorp', 'location': 'NYC'}]} >>> serializer = PersonSerializer(partial=True, instance=alice, data=data) >>> print(serializer.save()) Person(name='Alice', current_employer=Company('Acme Corp.', 'Los Angeles'), past_employers=[Company(name='OsCorp', location='NYC')])
如果您重写了 create() 或 update() 方法,传递给 validated_data 参数的数据类实例将具有特殊值 rest_framework.fields.empty,对于没有提供数据的任何字段。这是为了区分未提供的字段和具有默认值的字段,这在(常规和部分)更新时是必需的。您可以通过调用父类 update() 或 create() 方法来消除这些 empty 标记并将它们替换为默认值 - 这就是它们唯一要做的事情。
class CompanySerializer(DataclassSerializer): def create(self, validated_data): instance = super(CompanySerializer, self).create(validated_data) # if no value is provided for location, these will both hold assert validated_data.location == rest_framework.fields.empty assert instance.location is None # None is the default value of Company.location (see previous example)
序列器的 validated_data 属性上的这些 empty 标记也被清除,并替换为未提供字段的默认值。注意,这意味着您无法在部分更新中访问序列器的 validated_data,其中没有为没有默认值的字段提供数据,将抛出异常。
字段映射
迄今为止,支持以下类型及其子类的字段生成
str、bool、int 和 float。
datetime 包中的 date、datetime、time 和 timedelta。
decimal.Decimal(max_digits 和 decimal_places 分别默认为 None 和 2)。
uuid.UUID
enum.Enum(映射到 EnumField)
typing.Iterable(包括 typing.List 和 PEP 585 风格泛型,如 list[int])。
typing.Mapping(包括 typing.Dict 和 PEP 585 风格泛型,如 dict[str, int])。
typing.Literal(映射到 ChoiceField)
django.db.Model
序列器还支持具有上界或约束的类型变量。目前尚不支持类型联合。
对于高级用户,DataclassSerializer 还公开了一个 API,您可以通过它来重写以改变序列器字段生成的行为。
属性 serializer_field_mapping 包含一个映射类型到 REST 框架序列化器类的字典。您可以覆盖或扩展此映射以更改根据其类型使用的序列化器字段类。此字典还接受 dataclasses 作为键来更改用于嵌套 dataclasses 的序列化器。
serializer_related_field 属性用于模型关系的序列化器字段类。
serializer_dataclass_field 属性用于嵌套 dataclasses 的序列化器字段类。如果您通过子类化 DataclassSerializer 来自定义行为,您可能希望将此属性更改为使用子类。请注意,由于 Python 在定义类之前处理类体,因此此属性使用 property 装饰器 实现,以便它可以引用包含的类。
调用 build_unknown_field() 方法来创建未理解的 dataclasses 字段的序列化器字段。默认情况下,这会引发错误,但您可以通过自定义逻辑来扩展此功能以创建序列化器字段。
调用 build_property_field() 方法来创建方法的序列化器字段。默认情况下,这会创建一个只读字段,该字段具有方法的返回值。
build_standard_field()、build_relational_field()、build_dataclass_field()、build_enum_field()、build_literal_field() 和 build_composite_field() 方法分别用于处理字段、嵌套模型、嵌套 dataclasses、枚举、文字和列表或字典。可以通过覆盖它们来更改字段生成逻辑。
请注意,直到版本 1.0,这些 API 还未声明为稳定,如果需要,可能会更改。
项目详情
djangorestframework_dataclasses_piti-0.10-py3-none-any.whl 的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 4309a6a14b862f45cacaa49e78dbdf7f3a873e3d36d5ea6434ffd8725a0435c0 |
|
MD5 | c829e230bde52dee43145b2e04e24e5a |
|
BLAKE2b-256 | 9761750618c8fa40df111de1a2d934dc5e3bd5499b1bff2f281ffa39e8f2fe30 |