python-3.x-SqlAlchemy-多对多外部连接,并具有连接条件

这是我的代码:

Table('contacts', self.metadata,
    Column('id', PGUuid, primary_key=True),
    Column('first_name', String(150), nullable=False),
    Column('middle_name', String(150), nullable=True),
    Column('last_name', String(150), nullable=False, index=True),
    Column('friendly_name', String(150), nullable=True),
    Column('alias', String(450), nullable=False, index=True),
    Column('prefix', String(5), nullable=True),
    Column('suffix', String(5), nullable=True),
    Column('ssn', String(12), nullable=True),
    Column('email', String(150), nullable=True),
    Column('date_of_birth', Date, nullable=True),
    Column('contact_type', String(16), nullable=False))
    self._contacts_addresses_table = Table('contacts_addresses', self.metadata,
            Column('contact_id', PGUuid, ForeignKey('contacts.id'),
            primary_key=True, index=True),
            Column('address_id', PGUuid, ForeignKey('addresses.id'),
            primary_key=True, index=True))
    self._contacts_phones_table = Table('contacts_phones', self.metadata,
            Column('contact_id', PGUuid, ForeignKey('contacts.id'),
            primary_key=True, index=True),
            Column('phone_id', PGUuid, ForeignKey('phones.id'),
            primary_key=True, index=True))
    self._contacts_notes_table = Table('contacts_notes', self.metadata,
            Column('contact_id', PGUuid, ForeignKey('contacts.id'),
            primary_key=True, index=True),
            Column('note_id', PGUuid, ForeignKey('notes.id'),
            primary_key=True, index=True))

mapper(Contact, self._table, column_prefix='_', extension=ContextExtension(),
    properties={
        'addresses': relationship(Address, lazy='noload', secondary=self._contacts_addresses_table),
        'notes': relationship(Note, lazy='noload', secondary=self._contacts_notes_table),
        'phones': relationship(Phone, lazy='noload', secondary=self._contacts_phones_table),
        'contact_logs': relationship(ContactLog, lazy='noload')})

query(Contact).filter(Contact._id == contact_id) \
            .filter(Contact._is_deleted == False) \
            .outerjoin((Contact.addresses, Address)) \
            .options(contains_eager(Contact.addresses))

这是我的问题:在上面的查询中,我需要在外部联接上添加一个额外的条件.
如果我使用filter(Address.is_deleted == False),它将被添加到WHERE而不是JOIN ON子句中.

一些注意事项:我不使用延迟加载,也不想使用它.我不想对关系定义施加条件.实现此目的的一种方法是通过子查询.
但是在这种情况下,我也会遇到一些问题,如果我多次使用别名(或者如果SqlAlchemy这样做)相同的表,并且在外部联接中使用了这些别名表,则SqlAlchemy会创建错误的查询,最终会导致交叉联接,例如:从联系人,电话,地址中选择…

最佳答案
如果您需要的JOIN条件与relationship()定义的条件不同,则不能使用该关系进行联接.您必须明确说明:

query(Contact).filter(Contact._id == contact_id) \
            .filter(Contact._is_deleted == False) \
            .outerjoin(self._contacts_addresses_table) \
            .outerjoin(Address, and_(Address.id == self._contacts_address_table.c.address_id, Address.deleted == False)) \
            .options(contains_eager(Contact.addresses))

子查询方法也是可能的.我不确定您要在哪里查询,但是您描述的FROM子句问题表明您没有正确使用别名子查询对象.

如果是我,我只是添加一个附加的关系,称为“ non_deleted_addresses”,并带有viewonly = True和新条件,并将其用于联接.

转载注明原文:python-3.x-SqlAlchemy-多对多外部连接,并具有连接条件 - 代码日志