> On 17 Mar 2016, at 19:11, Alex Hall <ah...@autodist.com> wrote: > > Hello all, > It seems like I can't go a day without running into some kind of wall. > This one is a conceptual one regarding foreign keys. I have to somehow > get the same FK column in table A pointing to IDs in tables B and C. > > At one person's suggestion, I'm making classes for my tables, even > though I'm using automap. This is to let me stop doing a ton of joins, > making querying much easier... I hope! I'm defining all the foreign > keys between my tables manually. For instance: > > class item(base): > __tablename__ = "item" > itm_id = Column(Integer, primary_key=True) > vendornum = Column(String, ForeignKey(VENDR.PVVNNO)) > > class vendorTable(base): > __tablename__ = "VENDR" > PVVNNO = Column(String, primary_key=True) > > If I've understood correctly, I'll now be able to say > item.vendornum.vendor_full_name > to get the vendor's full name for any item. > > Here's the problem. Items have attachments, and attached text, > respectively held in attach and attach_text tables. Binding them to > items is a table called assignment. Assignment is pretty > straightforward, with an itm_id and an attachment id (att_id). The > trouble is that this att_id occurs in both attach and attach_text. I > can make att_id a foreign key to one table or the other, but I'm not > sure how to make it go to both tables. > > class assignmentTable(base): > __tablename__ = "assignment" > itm_id = Column(Integer, ForeignKey(item.itm_id)) > #the following column has to point to attach_text.att_id AS WELL > att_id = Column(Integer, ForeignKey(attachment.att_id)) > seq_num = Column(Integer) > asn_primary = Column(Integer, nullable=True) > > class attachmentTable(base): > __tablename__ = "attachment" > att_id = Column(Integer, primary_key=True) > > class attachmentTextTable(base): > __tablename__ = "attach_text" > att_id = Column(Integer, primary_key=True)
This isn’t possible - a foreign key can only point at one other column. If rows in attachment and attach_text are always supposed to be in a 1-to-1 relationship, you could consider one of them to be the “master” record, and make any other occurrences point to that. So for example, attachment.att_id could be the master id, and attach_text.att_id could be a foreign key pointing at attachment.att_id (perhaps with a unique constraint on it). The assignment table suggests that this is a many-to-many relationship (an attachment can belong to many items, and an item can have many attachments), so the relationships might be set up like this: item.assignments (list of assignmentTable objects) assignment.item (item object) assignment.attachment (attachmentTable object) attachmentTable.text (attachmentTextTable object) Here’s a working example: import sqlalchemy as sa import sqlalchemy.orm as saorm from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Item(Base): __tablename__ = 'item' itm_id = sa.Column(sa.Integer, primary_key=True) vendornum = sa.Column(sa.ForeignKey('vendr.pvvnno')) vendor = saorm.relationship('Vendor') assignments = saorm.relationship('Assignment', back_populates='item') class Vendor(Base): __tablename__ = 'vendr' pvvnno = sa.Column(sa.String(16), primary_key=True) vendor_full_name = sa.Column(sa.Text()) class Assignment(Base): __tablename__ = 'assignment' asn_primary = sa.Column(sa.Integer, primary_key=True) itm_id = sa.Column(sa.ForeignKey(Item.itm_id), nullable=False) att_id = sa.Column(sa.ForeignKey('attachment.att_id'), nullable=False) seq_num = sa.Column(sa.Integer) item = saorm.relationship('Item', back_populates='assignments') attachment = saorm.relationship('Attachment', back_populates='assignment') class Attachment(Base): __tablename__ = 'attachment' att_id = sa.Column(sa.Integer, primary_key=True) att_data = sa.Column(sa.Text()) assignment = saorm.relationship('Assignment', back_populates='attachment') text = saorm.relationship('AttachmentText', back_populates='attachment', uselist=False) class AttachmentText(Base): __tablename__ = 'attachmenttext' att_id = sa.Column(sa.ForeignKey('attachment.att_id'), primary_key=True) att_text = sa.Column(sa.Text()) attachment = saorm.relationship('Attachment', back_populates='text') if __name__ == '__main__': import sys engine = sa.create_engine('sqlite://', echo='debug') Base.metadata.create_all(bind=engine) Session = saorm.sessionmaker(bind=engine) session = Session() item = Item(vendor=Vendor(pvvnno='Alex', vendor_full_name='Alex the Vendor')) for i in range(5): attachment = Attachment(att_data=str(i), text=AttachmentText(att_text='text for %s' % i)) item.assignments.append(Assignment(attachment=attachment)) session.add(item) session.commit() del item del attachment session = Session() q = session.query(Item) if 'eager' in sys.argv: q = q.options( saorm.joinedload('vendor'), (saorm .joinedload('assignments') .joinedload('attachment') .joinedload('text')), ) item = q.first() print item print item.vendor for assignment in item.assignments: print assignment.attachment.att_data print assignment.attachment.text.at_text Hope that helps, Simon -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.