2017-11-09 4 views
0
여기

사용 관계는 내 모델입니다 .map_id "하지만 SQLAlchemy가"Map.id == user_map.map_id 및 Map.owner_id == user_map.user_id "를 사용하여 조인하려고합니다. 조인 조건을 어떻게 지정합니까?은 다 대다 SQLAlchemy의

관계에 primaryjoin 속성을 사용하고 .join() 내부의 조건을 지정하려고했지만 성공하지 못했습니다. 미리 감사드립니다!

+0

당신은 모든 사람들이 당신의 예제를 실행 할 수 있도록, 쿼리 코드를 게시하시기 바랍니다 수 있습니까? – jbndlr

+0

문서에서 예제를 따라 해 보았습니까? http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#many-to-many 매핑 테이블에 PrimaryKeyConstrain이 없어야합니다. –

+0

@jbndlr이 질문에 쿼리 코드를 추가했습니다. –

답변

0

코드를 기반으로 설정을 다시 작성했습니다. 나는 당신의 relationship가 섞여 있었다고 생각합니다. 또한 sqlalchemy의 다 대다 연관 테이블에서 기본 키 (또는 PrimaryKeyConstraints)를 거의 본 적이 없습니다. 그것은 비 Orm 관점에서 이해할 수 있지만, 내가 아는 한, 그것은 이상하거나 심지어 전혀 필요하지 않습니다.

import sqlalchemy as sa 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import relationship, sessionmaker 

Base = declarative_base() 

UsersXMaps = sa.Table(
    'users_x_maps', 
    Base.metadata, 
    sa.Column('user', sa.Integer, sa.ForeignKey('users.id')), 
    sa.Column('map', sa.Integer, sa.ForeignKey('maps.id')) 
) 

class User(Base): 
    __tablename__ = 'users' 
    id = sa.Column(sa.Integer, primary_key=True) 
    name = sa.Column(sa.String) 
    mail = sa.Column(sa.String, unique=True) 
    own_maps = relationship('Map', back_populates='owner') 
    maps = relationship(
     'Map', 
     secondary=UsersXMaps, 
     back_populates='users' 
    ) 

    def __str__(self): 
     return '{} ({}) with {} maps'.format(
      self.name, self.mail, len(self.own_maps)) 

class Map(Base): 
    __tablename__ = 'maps' 
    id = sa.Column(sa.Integer, primary_key=True) 
    name = sa.Column(sa.String) 
    owner_id = sa.Column(sa.Integer, sa.ForeignKey('users.id')) 
    owner = relationship('User', back_populates='own_maps') 
    users = relationship(
     'User', 
     secondary=UsersXMaps, 
     back_populates='maps' 
    ) 

    def __str__(self): 
     return '{} (by {})'.format(self.name, self.owner.name) 

지금까지 설정; 문자열을 출력 할 때 적절한 출력을 위해 약간 확장했습니다. 또한 Map.shared_maps 관계는 실제로 User을 나타내며 Map이 아니므로 해당 이름도 변경했습니다.

연관 테이블을 두 클래스에 바인딩 할 때 양쪽에서 참조 할 수 있습니다 (back_populates이 원래 정의를 덮어 쓰거나 바꾼 것처럼 보일지라도). 이렇게하면 양쪽에서 조인이 간단 해집니다.

예상대로 다음과 같은 작업을 실행 :

if __name__ == '__main__': 
    engine = sa.create_engine('sqlite:///usermaps.db') 
    sfactory = sessionmaker(engine) 

    session = sfactory() 

    Base.metadata.create_all(bind=engine) 

    bilbo = User(id=1, name='Bilbo', mail='[email protected]') 
    frodo = User(id=2, name='Frodo', mail='[email protected]') 

    mordor = Map(id=1, name='Mordor', owner=frodo, users=[bilbo, frodo]) 
    gondor = Map(id=2, name='Gondor', owner=bilbo, users=[bilbo, frodo]) 
    rohan = Map(id=3, name='Rohan', owner=bilbo, users=[bilbo, frodo]) 

    session.add_all([frodo, bilbo, mordor, gondor, rohan]) 
    session.commit() 

    print('Maps by owner:') 
    for owner in [bilbo, frodo]: 
     print(owner) 
     for item in session.query(Map).filter(Map.owner == owner).all(): 
      print(' - ' + str(item)) 

    print('Maps by users:') 
    for item in session.query(Map).filter(Map.users.any()).all(): 
     print(' - ' + str(item)) 

출력은 다음과 같습니다

Maps by owner: 
Bilbo ([email protected]) with 2 maps 
- Gondor (by Bilbo) 
- Rohan (by Bilbo) 
Frodo ([email protected]) with 1 maps 
- Mordor (by Frodo) 
Maps by users: 
- Mordor (by Frodo) 
- Gondor (by Bilbo) 
- Rohan (by Bilbo)