2017-03-15 7 views
2

현재 주식 포트폴리오를 처리하고 재정 분석을 할 수있는 Python (3.6)의 작은 응용 프로그램을 만들고 있습니다.SQLAlchemy ORM reconstructor의 대안

기능은 단순히 내 포트폴리오 및 주식에 대한 CRUD 인터페이스 (만들기, 읽기, 업데이트, 삭제)입니다. A의 위치

  • '비즈니스 로직'(: 그들은

    것은이 (ORM으로 PostgreSQL을하고 SQLAlchemy의 사용) dabase에서 지속 할 수있다, 나는 사이 절대 디커플링을 가진 목표로하고있다 등 내 파이썬 Stock 개체를 한 패키지 core), Portfolio, Regression,

  • 모든 SQLAlchemy의 메타 데이터와 core 패키지의 물체로 매핑이 분리 된 패키지 database)에 위치한 '지속성 계층'(def 이네

나는 여러 가지 이유로이 분리를 원하는 : 처음에는하고, 둘째, 나는 그것이 좋은 방법이라고 생각 (둘 다 어떤 DB가 설치되거나 심지어 SQLAlchemy의가와) 독립의 core 패키지를 실행 할 수 있도록하려면, 내 core 패키지, 정말 분석에 초점을 맞출 수 있기 때문 만이 아니라 낮은 수준의 SQLAlchemy의를 사용하여, 지금까지 그것을 할 관리 등 SQLA Column, relationships,

내 파이썬 객체를 '오염'mapperTable. 그러나 알아낼 수없는 유일한 점이 있습니다. 현재 내 파이썬 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() 같은 명령을 통해 예를 들어, (I 실제로 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를 사용하여 구독 할 수 있습니다. 자세한 내용은 [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

편집 :

응답은 "데이터 매퍼 그래서 당신은 당신의 데이터 계층과 비즈니스 계층에 걸쳐 하나 개의 데이터 클래스를 사용할 수 있습니다 instrusive되지 않는다", 의견을. 프로젝트가 작은 경우에만 해당됩니다. 그러나 프로젝트가 커지면 기본 데이터 저장소가 비즈니스 논리와 동일한 속도로 변경되지 않습니다. 그런 다음 어댑터, 변압기 등과 같은 중간 레이어가 필요합니다.

어쨌든 문제가 디커플링이 아니라면 @ orm.reconstructor 또는 해킹을 사용하십시오. 그렇지 않으면 가능한 한 최소한의 해킹이나 해결 방법을 사용하십시오.

====================================== 내 경험에

을 바탕으로 ORM 클래스는 사용자가 선택한 프레임 워크, SQLAlchemy, MongoEngine 등 어떤 기본 프레임 워크와도 결합됩니다.

미래에 데이터 저장소를 추상화하고 데이터 엔진을 전환 할 수 있습니다. 그런 다음 핵심 비즈니스 로직을 평범한 일부 오래된 클래스에 작성하는 것이 좋습니다. 그런 다음 저장소 모듈에서 ORM 클래스를 일반 클래스로 변환하는 함수를 제공하십시오.

예컨대 저장 패키지

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, 그리고 훨씬 더 쉽게 단위 테스트를 작성하려면 다음

# 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 

.

+0

"ORM 클래스는 기본 OMR 프레임 워크와 결합됩니다"는 액티브 레코드 기반 ORM에 대해서는 다소 사실이지만 데이터 매퍼에는 필요하지 않습니다 (OP는 이미 매핑을 사용하여 일반 클래스와 지속성으로 논리를 분리했습니다). –

+0

ORM은 orm입니다. 그것은 방해 적이며, 데이터 매퍼는 하나의 ORM 프레임 워크에서만 작동하며 자체 고유 한 특징을 가지고 있습니다. 그렇지 않으면 OP에는 이러한 문제가 없습니다. 의도는 한 가지, 구현은 또 다른 것입니다. @ IljaEverilä – Shuo

+0

[해킹이 필요 없습니다] (http://docs.sqlalchemy.org/en/latest/orm/events.html#sqlalchemy.orm.events.InstanceEvents.load). 'reconstructor()'데코레이터는 load 인스턴스 이벤트를 둘러싼 편리한 함수 일 뿐이므로 원하는 디커플링을 구현할 수 있습니다. –