如何在两个表上进行基本连接?

时间:2013-10-26 15:35:44

标签: python sqlalchemy

我正在学习SQLAlchemy,我在做看似简单的操作时遇到了麻烦。如果我的问题是原始的和基本的,请原谅我,但我不能为我的生活弄清楚如何基本上加入我的两个表。

我的表是这样的:

class User(Base):

    """ Basic User definition """

    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(Unicode(255))
    email = Column(Unicode(255), unique=True)
    username = Column(Unicode(255), unique=True)
    _password = Column('password', Unicode(60))

    contacts = relationship('Contact', backref='users')
    contact_groups = relationship('ContactGroups', backref='users')
    contact_group_users = relationship('ContactGroupUsers', backref='users')

class Contact(Base):

    __tablename__ = 'contacts'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer)
    contact_id = Column(Integer)

    __table_args__ = (ForeignKeyConstraint([contact_id], [User.id]), {})

class ContactGroups(Base):

    __tablename__ = 'contact_groups'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'))
    group_name = Column(Unicode(255))

    contact_group_users = relationship('ContactGroupUsers', backref='contact_groups')

class ContactGroupUsers(Base):

    __tablename__ = 'contact_group_users'

    id = Column(Integer, primary_key=True)
    group_id = Column(Integer, ForeignKey('contact_groups.id'))
    user_id = Column(Integer, ForeignKey('users.id'))

我有我的主User表。用户可以将其他用户添加为Contact。为了帮助组织这些联系人,他们可以创建ContactGroups

Contact.user_idContact.contact_id应该是User.id的外键。

ContactGroupUsers.group_idContactGroup.id的外键 每个ContactGroupUser.user_id都是返回该用户User.id的外键。 (也许这是一种可怕的方式......它可能是,但我正在学习。无论如何。)

当我查询特定组中的联系人时,我想检索filter(ContactGroupUsers.group_id == group_id).all()中的所有行,然后从中将ContactGroupUsers.user_id加入{{1}中的该用户的条目表。因此,我最终会得到一个结果:

Contact

那么,我的最后一个问题是,如何基于ContactGroupUsers.group_id | (and then the information present in the contacts table for that user) 加入我的两个表ContactGroupUsersContacts?或者,如果有一个固有的优越方法,请指出我正确的方向,所以我至少可以适当地学习。

感谢您的帮助。非常感谢。

1 个答案:

答案 0 :(得分:1)

由于您在User中将多个外键定义回Contact,因此最好按如下方式定义它们:

from sqlalchemy.ext.associationproxy import association_proxy

class User( Base ):

    __tablename__       = 'user'

    id                  = Column( Integer, primary_key=True )

    contacts            = relationship( 'Contact',
        primaryjoin = 'foreign( User.id )=remote( Contact.user_id )',
        backref     = 'user'
    )
    contact_groups      = relationship( 'ContactGroup', backref='user' )
    contact_group_users = relationship( 'ContactGroupUsers', backref='user' )

    contact_users = association_proxy( 'contacts', 'contact' )

class Contact( Base ):

    __tablename__       = 'contact'

    id                  = Column( Integer, primary_key=True )

    user_id             = Column( Integer, ForeignKey( 'user.id' ) )
    contact_id          = Column( Integer, ForeignKey( 'user.id' ) )

    contact             = relationship( 'User',
        primaryjoin = 'foreign( Contact.contact_id ) = remote( User.id )',
        backref     = 'user_contacts'
    )

class ContactGroup( Base ):

    __tablename__       = 'contact_group'

    id                  = Column( Integer, primary_key=True )

    user_id             = Column( Integer, ForeignKey( 'user.id' ) )

class ContactGroupUser( Base ):

    __tablename__       = 'contact_group_user'

    id                  = Column( Integer, primary_key=True )

    group_id            = Column( Integer, ForeignKey( 'contact_group.id' ) )
    user_id             = Column( Integer, ForeignKey( 'user.id' ) )

    contact_group       = relationship( 'ContactGroup' )

以这种格式构建关系可能有些复杂,涉及aliased个实例的用户。例如,您可以按如下方式进行查询,以指示某个group_id下的所有给定用户的联系人:

original_user = aliased( User )

contacts = db.session.query( User )\
    .join( User.user_contacts )\
    .join( original_user, original_user.id == Contact.user_id )\
    .join( User.contact_group_users )\
    .join( ContactGroupUser.contact_groups ).filter(
        and_(
             original_user.id == user_id,
             contact_group.user_id == original_user.id,
             contact_group.group_id == group_id
        )
     ).all()