2

SQLAlchemy の上にカスタム インターフェイスを作成して、事前定義されたハイブリッド プロパティが透過的にサポートされるようにしたいと考えています。

具体的には、クラスSpecialColumnとメタクラスを作成して、ユーザーがSpecialColumnクラスの属性として追加したときに、カスタム メタクラスがその属性を 2 つの SQLAlchemy に置き換え、Columnこれら 2 つの列をタプルとして取得および設定するハイブリッド プロパティを追加したいと考えています。これまでの私のアプローチは次のとおりです。

まず、特別な列タイプを定義しました。

class SpecialColumn(object):
     pass

次に、 DeclarativeMeta から継承するメタクラスを定義しました。これは、クラスをスキャンして のインスタンスを探し、それらを 2 つの とハイブリッド プロパティ (クロージャとして定義)SpecialColumnに置き換えます。Column

class MyDeclarativeMeta(DeclarativeMeta):

     def __new__(cls, name, bases, attrs):
          for name, col in attrs.items():
              if isinstance(col, SpecialColumn):
                  # Replacing the column
                  del attrs[name]
                  col1_name = '_{0}_1'.format(name)
                  col2_name = '_{0}_2'.format(name)
                  attrs[col1_name] = Column(...)
                  attrs[col2_name] = Column(...)
                  # Adding the hybrid property
                  def getter(self):
                      return (getattr(self, col1_name), getattr(self, col2_name))
                  attrs[name] = hybrid_property(getter)

最後にdeclarative_base、それを使用して のインスタンスを作成し、ユーザーが新しいベースでクラスを定義できるようにします。

MyBase = declarative_base(metaclass=MyDeclarativeMeta)

class MyClass(MyBase):
    col1 = SpecialColumn()
    col2 = Column(...)

私の質問のために:まず、私のアプローチは正しいですか?次に、メタクラスを使用してセッターを追加するにはどうすればよいですか? 次のようにするのは正しいでしょうか:

def setter(self, (v1, v2)):
    setattr(self, col1_name, v1)
    setattr(self, col2_name, v2)

そして、単に行うattrs[name].setter(setter)

4

1 に答える 1

7

SQLAlchemy でマップされたクラスにメタクラスを使用する必要はありません。クラスが作成および/またはマップされるときに、クラスに機能を追加するため のイベントが多数提供されているためです。ここではmapper_configuredMyBaseが良いかもしれません。0.8 を使用している場合は、直接適用できます。

@event.listens_for(MyBase, 'mapper_configured')
def get_special_columns(mapper, cls):
    for attrname in dir(cls):
        val = getattr(cls, attrname)
        if isinstance(val, SpecialColumn):
             name1, name2 = "_%s_1" % attrname, "_%s_2" % attrname
             setattr(cls, name1, Column(...))
             setattr(cls, name2, Column(...))

             @hybrid_property
             def myhybrid(self):
                 return getattr(self, name1), getattr(self, name2)

             @myhybrid.setter
             def myhybrid(self, value):
                 setattr(self, name1, value[0])
                 setattr(self, name2, value[1])

             setattr(cls, attrname, myhybrid)

setattr() は、ここに行くための最良の方法であり、単純で要点があることに注意してください。

于 2012-12-31T00:14:25.360 に答える