2017-02-14 12 views
1

내가이 같은 스키마를 가지고 말? 이 같은산들 스키마에서 프로그래밍 방식으로 필드를 정의

뭔가 :

class MyClass(BaseClass): 

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

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

나는 클래스 인스턴스에 동적 속성을 추가하는 방법에 대한 글을 본 적이 있지만이

  • 내가 인스턴스를 패치 싶지 않기 때문에 다른 있지만, 클래스
  • 산들 스키마 정의 메타 클래스를

의 S를 사용

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 

내가 만든 :

답변

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

위대한입니다. 특정 마시멜로 메커니즘보다는 파이썬 만 사용합니다. –

0

나는 기본 메타 클래스를 서브 클래 싱하여 수행하는 관리 AME 문제는 ODM/ORM (uMongo/MongoEngine, SQL 연금술, ...) 같은 다른 모델 정의 라이브러리에 적용 할 수 이보다 일반적인 : 다음 모든 필드 쉬 때문에

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 인스턴스입니다.

class Meta: 
     strict = True 
     auto_fields = [ 
      (FIELDS, 
      {'cls': Nested, 
       'args': (MyEmbeddedSchema), 
       'kwargs': {'required': True} 
      }), 
     ] 

내가 인해 동일한 인스턴스를 공유하는 여러 필드에있는 예를 사용하는 경우 실패가없는,하지만 안전 소리를하지 않습니다

Field과 그 인수는/kwargs로 별도로 지정해야합니다. 이주의 사항은 쓸모없는 경우 코드는 간단하고 읽기 쉽게 만들어 질 수 :

class Meta: 
     strict = True 
     auto_fields = [ 
      (FIELDS, Nested(MyEmbeddedSchema, required=True)), 
     ] 

물론,이 답변은 산들 바람에 고유 다른 ODM/ORM 라이브러리에는 적용되지 않습니다.