2017-02-14 12 views
1

は、私はこのようなスキーマを持っていると言う:マシュマロスキーマでプログラムのフィールドを定義し

class MySchema(Schema): 

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

はクラスに、プログラムでこれらのフィールドを追加する方法はありますか?このような

何か:

class MyClass(BaseClass): 

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

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

私は、クラスのインスタンスに動的に属性を追加する方法についての記事を見てきましたが、これは

  • が、私はインスタンスにパッチを適用したくないので、異なっているが、クラス
  • マシュマロスキーマのカスタムメタクラス

を使用していますAME質問(...、uMongo/MongoEngine、SQL錬金術)ODM/ORMのように、他のモデル定義ライブラリに適用される場合があります

答えて

4

あなたがする必要があるすべては、あなたが望む任意の属性を使用してクラスを構築するためにタイプ()機能を使用することです:

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

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

あなたも、そこにフィールドの種類を持つことができます

またはカスタマイズのベースとして:

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

これは素晴らしいです。特定のMarshmallowメカニズムではなくPythonを使用します。 –

0

私はデフォルトのメタクラスをサブクラス化することでそれを行うために管理:

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({fluid: Float()}) 
     return fields 

class MySchema(Schema, metaclass=MySchemaMeta): 

    class Meta: 
     strict = True 

私が作りましたこのより一般的な:すべてのこれらのフィールドは、shになるので

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インスタンスです。

Fieldとその引数/ kwargsからは、個別に指定する必要があります。

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)), 
     ] 

明らかに、この答えはマシュマロに固有のもので、他のODM/ORMライブラリーには適用されません。

関連する問題