1

我正在学习 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桌。用户可以将其他用户添加为Contacts。为了帮助组织这些联系人,他们可以创建ContactGroups.

Contact.user_id并且Contact.contact_id应该是User.id.

ContactGroupUsers.group_id是一个外键,ContactGroup.id 每个ContactGroupUser.user_id都是返回该用户的外键User.id。(也许这是一种糟糕的做法......可能是,但我正在学习。无论如何。)

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

ContactGroupUsers.group_id | (and then the information present in the contacts table for that user)

所以,我的最后一个问题是,我怎样才能加入我的两个表ContactGroupUsersContacts基于一个User.id?或者,如果有一种天生优越的方法可以做到这一点,请指出我正确的方向,这样我至少可以适当地学习。

谢谢你的帮助。非常感激。

4

1 回答 1

1

由于您将多个外键定义回Userin 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()
于 2013-12-11T20:12:25.063 回答