1

SQLAlchemyの宣言型ベースの子孫であるクラスがあります。宣言型ベースと実行中の別のシステムの間で変換されるブリッジオブジェクトを作成する必要がありますが、ブリッジオブジェクトがレコード内の列を正確に認識している必要がないようにする必要があります。その場合、レコード内のすべての列を一覧表示し、漠然と関連する2つの場所でのみ属性の一覧を維持する必要をなくし、その間のレプリケーションを最小限に抑える方法が必要です。これは、列属性を作成してから、列名の個別のリストを維持できることを意味しますが、繰り返しになりますが、レプリケーションが要因です。後でこの構造を変更したい場合は、両方の場所で変更する必要があります。

その場合、私はdictに列定義を貼り付けてから、dictを繰り返し処理して、次のようにsetattrを使用して各列定義を作成することを考えました。

    for k,v in self.__column_dict.items():
        setattr(self,k,
                sqlalchemy.Column(v['column_type'],**v.get('opts',{})),
                )

さて、ここにこすりがあります:クラスレベルでこのコードを貼り付けると、selfはまだ定義されておらず、エラーが発生します(これは理にかなっています)。これを貼り付けると__init__、selfが定義されますが、クラスの定義が完了するまでにテーブルに主キーがないため、SQLAlchemyの宣言型ベースでエラーが発生します(これらの属性は実行時まで設定されないため、これは理にかなっています) )。

つまり、すべてのことを言っても、evalを使用せずに必要なものを取得するにはどうすればよいですか、またはevalを使用しているのはここでの唯一のオプションですか?


編集:私は以下の解決策を受け入れましたが、それを100%使用しませんでした(それは私に答えを得るのに絶対に役立ちましたが)。これが私がやったことです:(DeclarativeMetaはsqlalchemy.ext.declarativeの一部であり、declarative_baseと同じパッケージであることに注意してください)

class MyMeta(DeclarativeMeta):
    def __new__(meta, classname, bases, dict_):
        klass = type.__new__(meta, classname, bases, dict_)
        if dict_.has_key('__classinit__'):
            klass.__classinit__ = staticmethod(klass.__classinit__.im_func)
        klass.__classinit__(klass, dict_)
        return klass

次に、私の派生クラスでは、

class DerivedClass(declarative_base()):
    __tablename__ = 'yaddayadda'
    __metaclass__ = MyMeta

    def __classinit__(klass, dict_):
        klass.__column_dict = <column dict here>

        for k,v in klass.__column_dict.items():
            setattr(klass,k,
                <fancy column stuff>
                )
   ...<rest of class definition>...
4

1 に答える 1

1

これは、declarative_baseとそのメタクラスにメタクラスを提供することで実行できます。

from sqlalchemy import Column, Integer
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta

class MyMeta(DeclarativeMeta): 

    def __init__(klass, classname, bases, dict_): 

        for k, v in dict_.items():

            if k.endswith('__column_dict'):

                for name, datatype, is_pk in v:

                    setattr(klass, name, Column(name, datatype, primary_key=is_pk))

        return DeclarativeMeta.__init__(klass, classname, bases, dict_)

Base = declarative_base(metaclass=MyMeta)

class Bob(Base):
    __tablename__ = 'bob'
    __column_dict = [('a', Integer, True), ('b', Integer, False)]

bob = Bob()
print bob.a
print bob.b
于 2011-04-20T21:00:01.413 に答える