2017-03-15 8 views
2

私は現在、株式のポートフォリオを処理し、財務分析を行うことができるPython(3.6)の小さなアプリケーションに取り組んでいます。SQLAlchemy ORM reconstructorの代替

機能は、私のポートフォリオと株のCRUDインターフェイス(作成、読み取り、更新、削除)です。に位置

  • のビジネスロジック '(:彼らは

    ものがある(ORMとしてPostgreSQLとSQLAlchemyの使用)dabaseに永続化することができ、私は間絶対デカップリングを持つ目指しています私はPythonがStockPortfolioRegressionなど

  • すべてSQLAlchemyのメタデータとcoreパッケージのオブジェクトとのマッピングがある()を分離パッケージdatabaseにある「永続化層を」、オブジェクトを持っているパッケージcore)、 def私はいくつかの理由から、この分離をしたい

をINED:最初の私は、スタンドアロンでcoreパッケージを起動できるようにする(任意のDBがインストールされていないどちらともさえSQLAlchemyの)と、第二に、私は、それは良い習慣だと思います私coreパッケージには、私は本当に分析に焦点を当てることができるためにすぎず、低レベルのSQLAlchemyのを使用して、私は今のところそれを行うには、管理などSQLA Columnrelationships

と私のPythonオブジェクトを「汚染」mapperTable。 しかし、私が理解できない点は1つだけです。現在、私のPython Stockオブジェクトは次のようである:

class Stock: 

    def __init__(self, ticker: str, exchange: Exchange, name: str=None): 
     self.ticker = ticker 
     self.exchange = exchange 
     self.name = name 
     self._data = None 

    ... 

_dataプロパティは私の財務データを格納するために必要な、と私はそれをインスタンス化したいです。あなたは私がsession.query(Stock).first()のようなコマンドを使用して、たとえば、(私は実際にdatabase PKGを使用する場合)、データベースからStockをロードする際に、その__init__機能がSQLAによって呼び出されていない、知っているかもしれないとして

しかし、 。私にできる唯一のことは、機能を追加している:ormsqlalchemy.ormで、私のcore PKGでsqlalchemyだけ輸入です

@orm.reconstructor 
def init_on_load(self): 
    self._data = None 

。私はそれを取り除きたいです!

アイデアはありますか?たとえばを通じてdatabaseパッケージ内の_dataプロパティをインスタンス化する方法がありますが、わかりません。

おかげ

+0

デフォルト値(この場合は 'None')が必要な場合は、' _data = None'をクラスレベルに置くことはできませんか? – univerio

+1

"[' reconstructor() '](http://docs.sqlalchemy.org/en/latest/orm/constructors.html#sqlalchemy.orm.reconstructor)は、より大きな「インスタンスレベル」イベントのシステムへのショートカットです。これらは、イベントAPIを使用してサブスクライブすることができます。これらのAPIの完全な説明については、[InstanceEvents](http://docs.sqlalchemy.org/en/latest/orm/events.html#sqlalchemy.orm.events.InstanceEvents)を参照してください。イベント "、そのうちの[' load'](http://docs.sqlalchemy.org/en/latest/orm/events.html#sqlalchemy.orm.events.InstanceEvents.load)に興味があるかもしれません。 –

+0

ありがとうございます。私は、イベント管理セクション、特にこのロードイベントを見て、あなたの言葉を引用して私の解答を投稿します。あなたが好きなのであれば、答えとしてあなたのコメントを再投稿して、私がそれを検証できるようにしてください! – Edouardb

答えて

-1

EDIT:コメントする

応答は、「データマッパーは、あなたのデータ層とビジネス層を横切って一つのデータクラスを使用することができますので、instrusiveされていません」。プロジェクトが小さい場合にのみそうです。プロジェクトが大きくなると、基盤となるデータストアはビジネスロジックと同じペースで変わることはありません。次に、アダプター、トランスなどの中間層が必要です。

とにかく、問題がデカップリングではない場合は、動作させたいだけで、@ orm.reconstructorやハックを使用してください。それ以外の場合は、ハックや回避策を可能な限り使用してください。私の経験に基づいて

======================================

ORMクラスは、あなたが選んだフレームワーク(SQLAlchemy、MongoEngineなど)に関係なく、基礎となるOMRフレームワークと結合されています。

将来、データストレージを抽象化し、データエンジンを切り替えることができます。次に、いくつかの普通の古いクラスにコアビジネスロジックを書き留めます。次に、記憶モジュールに、ORMクラスをプレーンクラスに変換する関数を提供します。

例えば

# module core.objects 
class Stock: 
    def __init(self, name, price): 
     self.name = name 
     self.price = price 

# business logic 
class BusinessLogic: 
    @staticmethod 
    def logic(stocks: list[Stock]): 
     pass 

そして、ストレージパッケージで

from core.objects import Stock as CoreStock 
# This is the ORM dependent class 
class Stock(Model): 
    name = columns.Text() 
    price = columns.Float() 

    @classmethod 
    def to_core_objects(instances): 
     return [CoreStock(instance.name, instance.price) for instance in instances] 

今、あなたは、ストレージエンジンは、MySQL、CSVなど、ユニットテストを記述する方がはるかに簡単に簡単に切り替えることができます。

+0

"ORMクラスは基になるOMRフレームワークと結合されています"というのは、Active RecordベースのORMには多少は当てはまりますが、データマッパーである必要はありません(OPは既にマッピングを使用してプレーンクラスと永続性でロジックを分離しています)。 –

+0

ORMはormです。それは邪魔です。データマッパーは1つのORMフレームワークでしか動作せず、独自のクォークを持っています。さもなければ、OPはそのような問題を持たない。意図は一つのことです、実装はもう一つです。 @IljaEverilä – Shuo

+0

[ハックは必要ありません](http://docs.sqlalchemy.org/en/latest/orm/events.html#sqlalchemy.orm.events.InstanceEvents.load) 'reconstructor()'デコレータは、ロードインスタンスイベントの周りの便宜上の機能に過ぎず、望ましいデカップリングが可能です。 –