Define fields programmatically in Marshmallow Schema

Jérôme picture Jérôme · Feb 14, 2017 · Viewed 8.6k times · Source

Say I have a Schema like this:

class MySchema(Schema):

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

Is there a way to add those fields programmatically to the class?

Something like this:

class MyClass(BaseClass):

    FIELDS = ('field_1', 'field_2',..., 'field_42')

    for field in FIELDS:
        setattr(?, field, Float())  # What do I replace this "?" with?

I've seen posts about adding attributes dynamically to class instances, but this is different because

  • I don't want to patch an instance but a class
  • Marshmallow Schema uses a custom metaclass

The same question might apply to other model definition libraries, like ODM/ORM (uMongo/MongoEngine, SQL Alchemy,...)

Answer

Maxim Kulkin picture Maxim Kulkin · Feb 15, 2017

All you need to do is to use type() function to build your class with any attributes you want:

MySchema = type('MySchema', (marshmallow.Schema,), {
    attr: marshmallow.fields.Float()
    for attr in FIELDS
})

You can even have different types of fields there:

fields = {}
fields['foo'] = marshmallow.fields.Float()
fields['bar'] = marshmallow.fields.String()
MySchema = type('MySchema', (marshmallow.Schema,), fields)

or as a base for your customizations:

class MySchema(type('_MySchema', (marshmallow.Schema,), fields)):
    @marshmallow.post_dump
    def update_something(self, data):
        pass