2014-08-27 8 views
1

피라미드에서 몇 관련 테이블과 쿼리를 생성 내가 정의한 몇 테이블 :SQLAlchemy의

# coding: utf-8 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import Integer, Float, DateTime, ForeignKey, ForeignKeyConstraint, String, Column 
from sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref, 
from zope.sqlalchemy import ZopeTransactionExtension 

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) 
Base = declarative_base() 


class Codes(Base): 
    __tablename__ = 'Code' 
    __table_args__ = {u'schema': 'Locations'} 

    id = Column(Integer, nullable=False) 
    code_str = Column(String(9), primary_key=True) 
    name = Column(String(100)) 

    incoming = relationship(u'Voyages', primaryjoin='Voyage.call == Codes.code_str', backref=backref('Code')) 


class Locations(Base): 
    __tablename__ = 'Location' 
    __table_args__ = {u'schema': 'Locations'} 

    unit_id = Column(ForeignKey(u'Structure.Definition.unit_id', ondelete=u'RESTRICT', onupdate=u'CASCADE'), primary_key=True, nullable=False) 
    timestamp = Column(DateTime, primary_key=True, nullable=False) 
    longitude = Column(Float) 
    latitude = Column(Float) 


class Voyages(Base): 
    __tablename__ = 'Voyage' 
    __table_args__ = (ForeignKeyConstraint(['unit_id', 'Voyage_id'], [u'Locations.Voyages.unit_id', u'Locations.Voyages.voyage_id'], ondelete=u'RESTRICT', onupdate=u'CASCADE'), {u'schema': 'Locations'} 
    ) 

    uid = Column(Integer, primary_key=True) 
    unit_id = Column(Integer) 
    voyage_id = Column(Integer) 
    departure = Column(ForeignKey(u'Locations.Code.code_str', ondelete=u'RESTRICT', onupdate=u'CASCADE')) 
    call = Column(ForeignKey(u'Locations.Code.code_str', ondelete=u'RESTRICT', onupdate=u'CASCADE')) 
    departure_date = Column(DateTime) 

    voyage_departure = relationship(u'Codes', primaryjoin='Voyage.departure == Codes.code_str') 
    voyage_call = relationship(u'Codes', primaryjoin='Voyage.call == Codes.code_str') 


class Definitions(Base): 
    __tablename__ = 'Definition' 
    __table_args__ = {u'schema': 'Structure'} 

    unit_id = Column(Integer, primary_key=True) 
    name = Column(String(90)) 
    type = Column(ForeignKey(u'Structure.Type.id', ondelete=u'RESTRICT', onupdate=u'CASCADE')) 

    locations = relationship(u'Locations', backref=backref('Definition')) 
    dimensions = relationship(u'Dimensions', backref=backref('Definition')) 
    types = relationship(u'Types', backref=backref('Definition')) 
    voyages = relationship(u'Voyages', backref=backref('Definition')) 


class Dimensions(Base): 
    __tablename__ = 'Dimension' 
    __table_args__ = {u'schema': 'Structure'} 

    unit_id = Column(ForeignKey(u'Structure.Definition.unit_id', ondelete=u'RESTRICT', onupdate=u'CASCADE'), primary_key=True, nullable=False) 
    length = Column(Float) 


class Types(Base): 
    __tablename__ = 'Type' 
    __table_args__ = {u'schema': 'Structure'} 

    id = Column(SmallInteger, primary_key=True) 
    type_name = Column(String(255)) 
    type_description = Column(String(255)) 

내가 여기서 뭘하려고하는 Codes 테이블에서 특정 행을 찾는 것입니다 (그것을 필터링 에 의해 code_str) 모든 관련 테이블을 얻지 만 Location 테이블이 timestamp에 의해 마지막 행만 반환하는 조건에서 에 의해 마지막 행만 반환해야하며 Definitions의 모든 정보를 가져야합니다.

은 내가 처음부터 쿼리를 작성하기 시작하고 이런 식 건너 온 :

string_to_search = request.matchdict.get('code') 

sub_dest = DBSession.query(func.max(Voyage.departure).label('latest_voyage_timestamp'), Voyage.unit_id, Voyage.call.label('destination_call')).\ 
    filter(Voyage.call== string_to_search).\ 
    group_by(Voyage.unit_id, Voyage.call).\ 
    subquery() 

query = DBSession.query(Codes, Voyage).\ 
    join(sub_dest, sub_dest.c.destination_call == Codes.code_str).\ 
    outerjoin(Voyage, sub_dest.c.latest_voyage_timestamp == Voyage.departure_date) 

하지만 난 내 결과 (for code, voyage in query를 같은)을 반복 할 때 나는 반복하는에게 실제로 내가 할 모든 Voyage임을 통지를 답례로. 이론적으로는 큰 문제는 아니지만 모든 가능한 경우를 포함하여 Codes 테이블의 기본 정보로 일부 json 응답을 구성하려고합니다. 예를 들어 :에 나는 각 루프에서이 code_data를 재 작성 좋아하지 않기 때문에 지금

code_data = {} 
all_units = [] 

for code, voyage in query: 
    if code_data is not {}: 
     code_data = { 
      'code_id': code.id, 
      'code_str': code.code_str, 
      'code_name': code.name, 
     } 

    single_unit = { 
     'unit_id': voyage.unit_id, 
     'unit_departure': str(voyage.departure_date) if voyage.departure_date else None, 
    } 
    all_units.append(single_unit) 

return { 
    'code_data': exception.message if exception else code_data, 
    'voyages': exception.message if exception else all_units, 
} 

이 조금 잘못된 것 같다, 그래서 여기 if code_data is not {} 라인을 넣어,하지만 난 그게 훨씬 더 (논리)이 될 것입니다 가정 다음 중첩 된 값으로 관련된 모든 Voyages있을 것입니다 (나는 특정 Code에 대한 DB를 조회 이후) 반환 만 단일 Code를 얻기 위해, 그래서

for code in query: 
    code_data = { 
     'code_id': code.id, 
     'code_str': code.code_str, 
     'code_name': code.name, 
    } 
    for voyage in code.voyages: 
     single_unit = { 
      'unit_id': voyage.unit_id, 
      'unit_departure': str(voyage.departure) if voyage.departure else None, 
     } 
     all_units.append(single_unit) 

return { 
    'code_data': exception.message if exception else code_data, 
} 

, 그리고이 유사한 방법으로 반복 물론, 각 Voyage에 관한 기타 모든 정보 ...

내 접근 방식은 처음부터 좋았으며 두 번째 방식으로 내 쿼리를 반복 작성하려면 어떻게해야합니까?

저는 Postgres 데이터베이스와 함께 Python 2.7.6, SQLAlchemy 0.9.7 및 Pyramid 1.5.1을 사용하고 있습니다.

감사합니다.

답변

1

외부 쿼리과 같이 변경해보십시오 : 그래서 같은 문제의 경우

query = DBSession.query(Codes).options(contains_eager('incoming')).\ 
    join(sub_dest, sub_dest.c.destination_call == Codes.code_str).\ 
    outerjoin(Voyage, sub_dest.c.latest_voyage_timestamp == Voyage.departure_date) 

, 옵션을 호출하려고 (...) 부분 :

(...) .options(contains_eager(Codes.incoming)). (...) 

이 하나 발생한다 Codes 인스턴스는 Voyages 개체로 정의 된 관계 (incoming)를 통해 액세스 할 수 있으므로 다음을 진행할 수 있습니다.

당신이 가져 오기를 필요 물론

, 예컨대 :이 도와위한 from sqlalchemy.orm import contains_eager

+0

감사합니다! 나는'contains_eager ('incoming')'과'contains_eager (Codes.incoming)'의 차이점을 궁금 할 뿐이니? 그것은 두 경우 모두에서 작동하지만 첫 번째 것이 궁극적 인 '문제'를 만드는 이유가 궁금합니다. – errata

+0

솔직하게 말하면, 나는 모른다. 문서는 첫 번째 버전을 "문자열 버전 [호출 중]"이라고하고 두 번째 버전은 "클래스 바인딩 된 설명자를 사용하는 [버전]"을 호출합니다. 두 개 이상의 엔티티가 같은 이름으로 관계가있는 여러 엔티티가있는 쿼리를 사용하면 어떤 일이 발생하는지 궁금 할 때를 제외하고는 정확히 동일하다고 확신합니다. 아마도 문자열 버전은 모호 할 것입니다. 나는 호기심에 그것을두고 간다 :) 그것은 기뻤다! !! – PawelP