Define fields programmatically in Marshmallow Schema

后端 未结 4 532
不思量自难忘°
不思量自难忘° 2021-02-09 05:27

Say I have a Schema like this:

class MySchema(Schema):

    field_1 = Float()
    field_2 = Float()
    ...
    field_42 = Float()

Is there a w

4条回答
  •  鱼传尺愫
    2021-02-09 06:09

    The following method works for me.

    I've demonstrated it using Marshmallow-SQLAlchemy because I'm not sure something like this is needed for plain Marshmallow anymore -- with version 3.0.0 it's pretty straightforward to programmatically create a schema using from_dict. But you could certainly use these concepts with plain Marshmallow.

    Here, I use Marshmallow-SQLAlchemy to infer most of the schema, and then apply special treatment to a couple of the fields programmatically.

    import enum
    
    from marshmallow_enum import EnumField
    from marshmallow_sqlalchemy import ModelSchema
    from sqlalchemy import Column
    from sqlalchemy import Enum
    from sqlalchemy import Integer
    from sqlalchemy import String
    from sqlalchemy.ext.declarative import declarative_base
    
    
    BaseResource = declarative_base()
    
    
    class CustomEnum(enum.Enum):
        VALUE_1 = "the first value"
        VALUE_2 = "the second value"
    
    
    class ExampleResource(BaseResource):
        __tablename__ = "example_resource"
    
        id = Column(Integer, primary_key=True)
        enum_field = Column(Enum(CustomEnum), nullable=False)
        title = Column(String)
        string_two = Column(String)
    
        def __init__(self, **kwargs):
            super(ExampleResource, self).__init__(**kwargs)
    
    
    def generate_schema(class_, serialization_fields, serialization_fields_excluded):
        """A method for programmatically generating schema.
    
        Args:
            class_ (class): the class to generate the schema for
            serialization_fields (dict): key-value pairs with the field name and its Marshmallow `Field`
            serialization_fields_excluded (tuple): fields to exclude
    
        Returns:
            schema (marshmallow.schema.Schema): the generated schema
    
        """
    
        class MarshmallowBaseSchema(object):
            pass
    
        if serialization_fields is not None:
            for field, marshmallow_field in serialization_fields.items():
                setattr(MarshmallowBaseSchema, field, marshmallow_field)
    
        class MarshmallowSchema(MarshmallowBaseSchema, ModelSchema):
            class Meta:
                model = class_
                exclude = serialization_fields_excluded
    
        return MarshmallowSchema
    
    
    generated_schema = generate_schema(
        class_=ExampleResource,
        # I'm using a special package to handle the field `enum_field`
        serialization_fields=dict(enum_field=EnumField(CustomEnum, by_value=True, required=True)),
        # I'm excluding the field `string_two`
        serialization_fields_excluded=("string_two",),
    )
    
    example_resource = ExampleResource(
        id=1,
        enum_field=CustomEnum.VALUE_2,
        title="A Title",
        string_two="This will be ignored."
    )
    print(generated_schema().dump(example_resource))
    # {'title': 'A Title', 'id': 1, 'enum_field': 'the second value'}
    

    It's necessary to define MarshmallowBaseSchema as a plain object, add all the fields, and then inherit from that class because the Marshmallow Schema initializes all the fields on init (in particular, _init_fields()), so this inheritance pattern makes sure all the fields are there at that time.

提交回复
热议问题