2012-03-14 3 views
15

주로 호기심 때문에 도메인 로직에서 영속성 로직을 디커플링하는 저장소 패턴에 대한 Python 프레임 워크 또는 예제를 찾고있다.파이썬에서 저장소 패턴 구현하기?

이름은 "저장소 패턴", 아이디어는 "도메인 구동 형 디자인"책의 sectionMartin Fowler에서 온다 (루비) 포스트 "Untangle Domain and Persistence Logic with Curator"에 나타납니다. 모델 클래스에는 지속성 로직이 없습니다. 대신 인스턴스가 모델 인스턴스의 메모리 내 컬렉션처럼 작동하는 저장소 하위 클래스를 선언합니다. 각 저장소는 SQL (다양한 스키마 규칙), Riak 또는 기타 noSQL 및 메모리 (캐싱 용)와 같은 다른 방법으로 모델을 유지합니다. 프레임 워크 규칙은 저장소 하위 클래스가 일반적으로 최소한의 코드 만 필요로한다는 것을 의미합니다. SQLRepository의 "WidgetRepository"하위 클래스를 선언하면 모델 위젯을 "widgets"라는 DB 테이블에 유지하고 열을 위젯 속성에 일치시키는 컬렉션을 제공합니다. 다른 패턴에서

차이 :

액티브 레코드 패턴 : 예를 들어, 장고 ORM. 응용 프로그램은 도메인 논리 및 지속성을위한 일부 메타 데이터가있는 모델 클래스 만 정의합니다. ORM은 퍼시스턴스 로직을 모델 클래스에 추가합니다. 이것은 도메인과 영속성을 하나의 클래스에 혼합합니다 (게시물에 따라 바람직하지 않습니다).

@marcin 덕분에 Active Record가 다양한 백엔드를 지원하고 .save (= "other_database") 함수를 사용할 때 저장소 패턴의 다중 백엔드 이점을 제공한다는 것을 알 수 있습니다.

그런 의미에서 저장소 패턴은 지속성 논리가 별도의 클래스로 이동 된 활성 레코드와 같습니다.

데이터 매퍼 패턴 : 예 : SQLAlchemy의 클래식 매핑. 이 앱은 데이터베이스 테이블과 모델에서 테이블로의 데이터 매퍼에 대한 추가 클래스를 정의합니다. 따라서, 모델 인스턴스는 테이블에 여러 방식으로 매핑 될 수있다. 레거시 스키마를 지원합니다. SQLAlchemy가 SQL 이외의 저장소에 매퍼를 제공한다고 생각하지 마십시오.

+0

연구에서 제안하는 내용은 무엇입니까? 나는 방금 여러 가지 대안을 굉장히 많이 봤다. – Marcin

+0

''python ''저장소 패턴 "에 대한 인터넷 검색은 구현을 수행하지 않습니다. 정확히 무엇을 검색 했습니까? – Graham

+0

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

답변

1

당신은에서 좋은 모습을 할 수 있습니다 제임스 데니스 'DictShield project

"DictShield 데이터베이스에 독립적 모델링 시스템입니다. 그것은 모든 특정 데이터베이스를 필요로하지 않고. 쉽게 데이터를 모델의 유효성을 검사하고 바꿀 수있는 방법을 제공합니다 . " 내 머리에서

+0

DictShield는 모델링, 검증 및 관련 모델을위한 헬퍼를 제공합니다. 저장소 패턴은 다양한 백엔드에 대해 콜렉션과 유사한 클래스를 제공합니다. – Graham

7

:

나는 두 가지 예를 들어 도메인, UserAnimal, 기본 저장 클래스 Store 두 개의 전문 스토리지 클래스 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

이 접근법을 사용하여 리포지토리가 작동하도록 할 수 있습니다. 데이터베이스 Agnostics의 경우 [SQLAlchemy] (http://www.sqlalchemy.org/)를 사용하여 내부를 구현하십시오. – famousgarkin