Domanda

Here is my code:

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))

Here is my issue: In the above query I need to add an extra condition on the outer join. If I use filter(Address.is_deleted == False) it will be added on the WHERE and not on the JOIN ON clause.

Some notes: I am not using lazy loading and I do not want to use it. I do not want to enforce the condition on relation definition. One way to achieve this is through subqueries. But I have some issues in that case also, if I alias (or if SqlAlchemy does it) same tables multiple times and those aliased tables are used in an outer join, SqlAlchemy creates a wrong query, I end up with a cross join such as: SELECT ... FROM contacts, phones, addresses ...

È stato utile?

Soluzione

if you need a JOIN condition different from what the relationship() defines, then you can't use that relationship to do the join. You have to spell it out explcitly:

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))

the subquery method is also possible. I'm not sure what query you're looking for there but the FROM clause issue you describe indicates you're not using the aliased subquery object appropriately.

if it were me, I'd just add an additional relationship called "non_deleted_addresses" with viewonly=True and the new criteria, and use that for the join.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top