我设法通过继承默认元类来做到这一点:
class MySchemaMeta(SchemaMeta):
@classmethod
def get_declared_fields(mcs, klass, cls_fields, inherited_fields, dict_cls):
fields = super().get_declared_fields(klass, cls_fields, inherited_fields, dict_cls)
FIELDS = ('field_1', 'field_2',..., 'field_42')
for field in FIELDS:
fields.update({field: Float()})
return fields
class MySchema(Schema, metaclass=MySchemaMeta):
class Meta:
strict = True
我使这个更通用:
class DynamicSchemaOpts(SchemaOpts):
def __init__(self, meta):
super().__init__(meta)
self.auto_fields = getattr(meta, 'auto_fields', [])
class DynamicSchemaMeta(SchemaMeta):
@classmethod
def get_declared_fields(mcs, klass, cls_fields, inherited_fields, dict_cls):
fields = super().get_declared_fields(klass, cls_fields, inherited_fields, dict_cls)
for auto_field_list in klass.opts.auto_fields:
field_names, field = auto_field_list
field_cls = field['cls']
field_args = field.get('args', [])
field_kwargs = field.get('kwargs', {})
for field_name in field_names:
fields.update({field_name: field_cls(*field_args, **field_kwargs)})
return fields
class MySchema(Schema, metaclass=DynamicSchemaMeta):
OPTIONS_CLASS = DynamicSchemaOpts
class Meta:
strict = True
auto_fields = [
(FIELDS,
{'cls': Float}),
]
我没写
class Meta:
strict = True
auto_fields = [
(FIELDS, Float()),
]
因为那样所有这些字段将共享同一个Field
实例。
及其 args/ kwargsField
必须单独指定:
class Meta:
strict = True
auto_fields = [
(FIELDS,
{'cls': Nested,
'args': (MyEmbeddedSchema),
'kwargs': {'required': True}
}),
]
由于多个字段共享同一个实例,我没有任何示例用例失败,但这听起来并不安全。如果这种预防措施没有用,那么可以简化代码并使其更具可读性:
class Meta:
strict = True
auto_fields = [
(FIELDS, Nested(MyEmbeddedSchema, required=True)),
]
显然,这个答案是针对 Marshmallow 的,不适用于其他 ODM/ORM 库。