2016-06-13 1 views
4

SQLAlchemy (일반적으로 ORM)를 처음 사용하고 SQLAlchemy로 기존 응용 프로그램을 이동하려고합니다. 따라서 현재 존재하는 (지루한 업데이트) 쿼리의 코드 복잡성을 일부 변경할 수 있습니다 , 파이썬. 불행히도, 나는 데이터베이스 반영 후 즉시 오류가 발생합니다. 표를 직접 쿼리 할 수는 있지만 실제로 클래스에 직접 액세스하거나 클래스 간의 관계는 없습니다. 아래는 내가하려는 일의 대략적인 예입니다.SQLAlchemy 역 참조 오류를 자동화하십시오.

기존 포스트 그레스 테이블 :

dev=> \d+ gmt_file 
             Table "public.gmt_file" 
    Column |  Type  | Modifiers | Storage | Stats target | Description 
-----------+--------------+-----------+----------+--------------+------------- 
file_id | integer  | not null | plain |    | 
     a | integer  |   | plain |    | 
     b | integer  |   | plain |    | 
Indexes: 
    "gmt_file_pk" PRIMARY KEY, btree (file_id) 
Foreign-key constraints: 
    "gmt_file_a_fk" FOREIGN KEY (a) REFERENCES cmn_user(user_id) 
    "gmt_file_b_fk" FOREIGN KEY (b) REFERENCES cmn_user(user_id) 

SQLAlchemy의 응용 프로그램 (최소한의 예) :

내가 지금까지 무엇을 말할 수에서
from sqlalchemy import create_engine 
from sqlalchemy.orm import Session,Mapper 
from sqlalchemy.ext.automap import automap_base 

engine = create_engine('postgresql://user:[email protected]:5432/dev') 
Base = automap_base() 
Base.prepare(engine, reflect=True) 
session = Session(engine,autocommit=True) 

session.query(Base.classes.gmt_file).all() 

,이 때문에 모두 ab 가진의 역 참조 오류가 발생합니다 다른 테이블의 같은 필드와의 외래 키 관계 (이것은 기존 DB에서 자주 발생합니다). 사용자 지정 명명 함수 (name_for_scalar_relationship()name_for_collection_relationship())를 만드는 등 여러 가지 방법으로이 오류를 처리하려고했지만 아무 소용이 없었습니다. SQLAlchemy에서 이것을 처리하거나 반사 중에 역 참조 생성을 비활성화하는 표준 방법이 있습니까?

궁극적 인 목표는 DB를 자동화 된 방식으로 반영하는 것일뿐 현재 존재하는 수백 개의 테이블에 대한 사용자 지정 이름 매핑을 작성할 필요가 없지만 무엇을 해야할지를 놓치고 있습니다. 어떤 도움을 주셔서 감사합니다.

우리가 하나 이상의 외부 키가 같은 열을 참조 할 때 오토를 사용하여 속성 이름의 충돌을 얻을 것 같습니다

+0

이것이 해결책을 찾는 데 도움이되는지 확신 할 수 없지만 '__table__'하위 객체를 사용하여 직접 테이블을 질의 할 수 있습니다. 예 : 'session.query (Base.classes.gmt_file .__ table __). all()'은 에러를 던지지 않습니다. 이견있는 사람? – DavidWayne

답변

1

주셔서 감사합니다.

Base.prepare은 속성 이름을 생성하는 데 사용되는 함수를 사용하는 인수 name_for_scalar_relationshipname_for_collection_relationship을 허용합니다. (AutomapBase.prepare()name_for_collection_relationship()에 대한 설명서 참조) 내 자신의 기능을 정의하여 역 참조 오류를 해결할 수있었습니다.

당신의 최소한의 예를 수정 :

from sqlalchemy import create_engine 
from sqlalchemy.orm import Session,Mapper 
from sqlalchemy.ext.automap import automap_base, name_for_collection_relationship 

engine = create_engine('postgresql://user:[email protected]:5432/dev') 
Base = automap_base() 

def _name_for_collection_relationship(base, local_cls, referred_cls, constraint): 
    if constraint.name: 
     return constraint.name.lower() 
    # if this didn't work, revert to the default behavior 
    return name_for_collection_relationship(base, local_cls, referred_cls, constraint) 

Base.prepare(engine, reflect=True, name_for_collection_relationship=_name_for_collection_relationship) 
session = Session(engine,autocommit=True) 

session.query(Base.classes.gmt_file).all() 

이 희망 속성 이름 gmt_file_a_fkgmt_file_b_fk 당신에게 수업을 받아야합니다.

이 방법은 저에게 효과적입니다. 작동하지 않으면 마찬가지로 name_for_scalar_relationship()을 재정의 할 수도 있습니다.

클래스를 전혀 덮어 쓰지 않으려면 열과 관계를 올바르게 정의해야합니다. 예 :

from sqlalchemy import Column, Integer, ForeignKey 
from sqlalchemy.orm import relationship 

class GmtFile(Base): 
    __tablename___ = 'gmt_file' 

    file_id = Column('file_id', Integer, primary_key=True) 

    a = Column('a', Integer, ForeignKey('CmnUser.user_id', name='gmt_file_a')) 
    b = Column('b', Integer, ForeignKey('CmnUser.user_id', name='gmt_file_b')) 
    # you'll need to define the class CmnUser as well 

    # these variable names need to be the same as the ForeignKey names above 
    gmt_file_a = relationship('CmnUser', foreign_keys=[a]) 
    gmt_file_b = relationship('CmnUser', foreign_keys=[b]) 
+0

그것은 나를 위해 작동합니다. 감사합니다. 필요할 때 바로 대답했습니다 :). – Frane

+0

SQLAlchemy에서 옮겼습니다. 따라서이 경우에는 제대로 작동하는지 확인하지 못했습니다. 그러나 문제가 해결 될 수 있고 다른 사람의 문제를 해결하기 때문에 올바르게 표시하고 있습니다. – DavidWayne