2012-03-14 135 views
15

主に、好奇心から、ドメインロジックから永続性ロジックを分離するリポジトリパターンのPythonフレームワークまたは例を探しています。Pythonでのリポジトリパターンの実装?

ポスト "Untangle Domain and Persistence Logic with Curator"(Ruby)に名前が "Repository Pattern"という名前が表示され、アイデアは "Domain-Driven Design"ブックのsectionMartin Fowlerから得られます。モデルクラスには永続ロジックが含まれておらず、インスタンスはモデルインスタンスのメモリ内コレクションのように動作するリポジトリサブクラスを宣言します。各リポジトリは、SQL(さまざまなスキーマ規則)、Riakやその他のnoSQL、メモリ(キャッシュ用)など、さまざまな方法でモデルを保持します。 SQLRepositoryの "WidgetRepository"サブクラスを宣言するだけで、モデルウィジェットを "widgets"という名前のDBテーブルに保存し、列をウィジェット属性に一致させるコレクションが提供されます。他のパターンから

違い:

のActive Recordパターン:例えば、DjangoのORM。アプリケーションは、ドメインロジックと永続性のためのメタデータを持つモデルクラスを定義します。 ORMは、パーシスタンスロジックをモデルクラスに追加します。これは、ドメインと永続性を1つのクラスに混在させます(ポストによれば望ましくない)。

@marcinのおかげで、Active Recordが多様なバックエンドと.save(= "other_database")関数をサポートすると、リポジトリパターンのマルチバックエンドの利点が得られることが分かります。

リポジトリパターンは、永続ロジックを別のクラスに移動したアクティブレコードと同じ意味です。

データマッパーパターン:たとえば、SQLAlchemyの古典的なマッピング。このアプリケーションは、データベーステーブルとモデルからテーブルへのデータマッパーの追加クラスを定義します。したがって、モデルインスタンスは、複数の方法でテーブルにマッピングすることができる。レガシースキーマをサポートします。 SQLAlchemyが非SQLストレージにマッパーを提供しているとは思わないでください。あなたはジェームズ・デニスのDictShield project

「DictShieldは、データベースに依存しないモデリング・システムである。それは、モデルの検証と簡単にデータを再構築する方法を提供します。すべての任意の特定のデータベースを必要とせずに良い顔をしているしたい場合があります

+0

あなたの研究は何を示唆していますか?私はちょうど簡単にいくつかの選択肢を検索しました。 – Marcin

+0

'' python ''リポジトリパターンのためのグーグリングは実装をまったくしません。あなたは何を正確に探しましたか? – Graham

+0

http://www.google.co.uk/search?q=django+orm+backend – Marcin

答えて

1

"私の頭のうち

+0

DictShieldはモデルのモデリング、検証、関連するヘルパーを提供します。リポジトリパターンは、さまざまなバックエンドのためのコレクションのようなクラスを提供します。 – Graham

7

私は2つの例ドメイン、UserAnimal、ベースのストレージ・クラスStoreと2つの特殊なストレージクラスUserStoreAnimalStoreを定義します。コンテキストマネージャを使用するとdb接続が終了します(この例では簡単にsqliteを使用しています)。

import sqlite3 

def get_connection(): 
    return sqlite3.connect('test.sqlite') 

class StoreException(Exception): 
    def __init__(self, message, *errors): 
     Exception.__init__(self, message) 
     self.errors = errors 


# domains 

class User(): 
    def __init__(self, name): 
     self.name = name 


class Animal(): 
    def __init__(self, name): 
     self.name = name 


# base store class 
class Store(): 
    def __init__(self): 
     try: 
      self.conn = get_connection() 
     except Exception as e: 
      raise StoreException(*e.args, **e.kwargs) 
     self._complete = False 

    def __enter__(self): 
     return self 

    def __exit__(self, type_, value, traceback): 
     # can test for type and handle different situations 
     self.close() 

    def complete(self): 
     self._complete = True 

    def close(self): 
     if self.conn: 
      try: 
       if self._complete: 
        self.conn.commit() 
       else: 
        self.conn.rollback() 
      except Exception as e: 
       raise StoreException(*e.args) 
      finally: 
       try: 
        self.conn.close() 
       except Exception as e: 
        raise StoreException(*e.args) 


# store for User obects 
class UserStore(Store): 

    def add_user(self, user): 
     try: 
      c = self.conn.cursor() 
      # this needs an appropriate table 
      c.execute('INSERT INTO user (name) VALUES(?)', (user.name,)) 
     except Exception as e: 
      raise StoreException('error storing user') 


# store for Animal obects 
class AnimalStore(Store): 

    def add_animal(self, animal): 
     try: 
      c = self.conn.cursor() 
      # this needs an appropriate table 
      c.execute('INSERT INTO animal (name) VALUES(?)', (animal.name,)) 
     except Exception as e: 
      raise StoreException('error storing animal') 

# do something 
try: 
    with UserStore() as user_store: 
     user_store.add_user(User('John')) 
     user_store.complete() 

    with AnimalStore() as animal_store: 
     animal_store.add_animal(Animal('Dog')) 
     animal_store.add_animal(Animal('Pig')) 
     animal_store.add_animal(Animal('Cat')) 
     animal_store.add_animal(Animal('Wolf')) 
     animal_store.complete() 
except StoreException as e: 
    # exception handling here 
    print(e) 
+0

はい、これはリポジトリパターンを実装します。それを提供するライブラリでは、各ストレージバックエンドがモデルをストレージにマップするためのデフォルト戦略を提供することを望んでいるので、手書きのSQLは必要ありません。 – Graham

+1

@graham [SQLAlchemy](http://www.sqlalchemy.org/)はあなたの望むものかもしれませんが、軽量ではありません。[SQLAlchemy session](http://docs.sqlalchemy.org/en/latest/orm /session.html)。 – laurasia

+0

この方法を使用して、リポジトリを機能させることができます。データベースの不具合については、[SQLAlchemy](http://www.sqlalchemy.org/)を使用して内部を実装してください。 – famousgarkin