Excellent, that worked! It took a little tweaking, but I figured out how to define the foreign keys. Note: this syntax is using Flask-SQLAlchemy so there's no metadata defined.
reference_assoc = db.Table('reference_assoc', db.Column('object_key',db.Integer()), db.Column('refs_key',db.Integer,db.ForeignKey('reference.refs_key')), db.Column('type_key',db.Integer()), ) Marker.references = db.relationship("Reference", secondary=reference_assoc, primaryjoin=db.and_(Marker.marker_key==reference_assoc.c.object_key, reference_assoc.c.type_key==1), secondaryjoin=(reference_assoc.c.refs_key==Reference.refs_key), foreign_keys=[Marker.marker_key,Reference.refs_key], backref="markers", ) One minor peculiarity is that I had to add a ".c" after reference_assoc to access each column. Otherwise I get this error: AttributeError: 'Table' object has no attribute 'object_key' Anyway, thanks for your help. On Wed, Mar 27, 2013 at 5:46 PM, Simon King <si...@simonking.org.uk> wrote: > When you model a many-to-many relationship in SQLAlchemy, you have a > choice whether or not to map a class to the intermediate table. Generally, > you only need to map that table if you want to get instances back from the > ORM that represent those rows (presumably so that you can manipulate the > values). When you do this, you don't really have a many-to-many > relationship any more. Instead, you have a one-to-many relationship on one > side of the intermediate class, and a many-to-one on the other side. SA > refers to this pattern as an Association Object ( > http://docs.sqlalchemy.org/en/rel_0_8/orm/relationships.html#association-object > ) > > In your case (as long as you are staying read-only), I don't think there > is any need to map the intermediate table. Your code would look more like > the example at > http://docs.sqlalchemy.org/en/rel_0_8/orm/relationships.html#many-to-many, > where the Reference_Assoc table is a Table instance, rather than a mapped > class. Your Marker.references relationship would then look something like > this: > > reference_assoc = Table('reference_assoc', Base.metadata, > # reference_assoc columns go here > ) > > Marker.references = relationship( > Reference, > secondary=reference_assoc, > primary_join=and_(Marker.marker_key == reference_assoc.object_key, > reference_assoc.type_key == 1), > secondary_join=(reference_assoc.ref_key == Reference.ref_key), > backref='markers', > ) > > (That almost certainly won't work first time, but if you let us know what > the errors are we'll try to help) > > Simon > > On 27 Mar 2013, at 17:28, Kevin S <kevinrst...@gmail.com> wrote: > > > Ok, I'm sorry to be confusing. But this backref thing, it isn't > returning "random" results, but the join condition is all wrong. > > > > It is taking a ReferenceAssoc object with type_key = 11 and > object_key=215, and making the where clause I showed. > > So I get back a marker with marker_key 215, but really that > referenceAssoc is not for a marker but for some other type. > > It should not bring back any markers. > > > > > > On Wednesday, March 27, 2013 1:14:43 PM UTC-4, Kevin S wrote: > > Also, is it appropriate to define a backref here? It returns wrong data. > When I get a ReferenceAssoc object and get its marker, it generates a query > with a clause like: > > "reference_assoc._mgitype_key = @_mgitype_key_1 AND @param_1 = > marker._marker_key" > > and these params : {'@_mgitype_key_1': 2, '@param_1': 215} > > > > That does not make sense as SQL and just returns a random marker. > > > > On Wednesday, March 27, 2013 1:05:26 PM UTC-4, Kevin S wrote: > > Thanks. I have it working for the Marker to Reference_Assoc relationship: > > Marker.referenceAssocs = relationship("ReferenceAssoc", > > primaryjoin="""and_(ReferenceAssoc._mgitype_key==2, > > ReferenceAssoc._object_key==Marker._marker_key)""", > > foreign_keys=[Marker._marker_key], > > backref="marker", > > uselist=True, > > ) > > > > However, that is just a one to many relationship. I am not certain how > to expand that to define Marker.references. Which essentially translates to > Marker => ReferenceAssoc => Reference. > > > > I am not sure how many relationships I need and on which classes to > define them. > > > > On Wednesday, March 27, 2013 12:48:23 PM UTC-4, Simon King wrote: > > On Wed, Mar 27, 2013 at 4:13 PM, Kevin S <kevin...@gmail.com> wrote: > > > Setup: I have been learning SQL Alchemy to build a prototype (proof of > > > concept) Flask app for our internal website. We want to replace our > current > > > site, which is made entirely of slow python CGIs and raw SQL. Our > database > > > (Postgres) is fairly large, but has some unusual table relationships, > and is > > > highly normalized in regards to data entry (BUT, I am only interested > in a > > > read only interface at the moment. I.e. queries and summaries). My > goal is > > > to see how well SQL Alchemy can handle some of these relationships. > Whether, > > > it is being able to fully define the relationships in the model, or if > we > > > have to define the basic objects and use join syntax at query time, I > just > > > want to know what's possible. > > > > > > Ok, so here is one example that I haven't been able to figure out the > > > correct way to do (There is a lot you can do in SQLAlchemy!). I won't > go > > > into all my failed attempts. > > > We have a join table (several like it actually) that holds many > different > > > types of object relationships in it. You specify the correct join > conditions > > > using a type key. > > > Say these are the tables: > > > Marker, Allele, Reference_Assoc, Reference. > > > > > > You get markers for a reference by doing "Reference.ref_key = > > > Reference_Assoc.ref_key AND > Reference_Assoc.object_key=Marker.marker_key AND > > > Reference_Assoc.type_key=1". > > > However you can also get alleles for a reference by doing > "Reference.ref_key > > > = Reference_Assoc.ref_key AND > Reference_Assoc.object_key=Allele.allele_key > > > AND Reference_Assoce.type_key=2" > > > > > > I don't know a whole lot about database patterns, so I don't know what > this > > > relationship would be called. However, this database schema is not > changing > > > anytime soon, so I'm stuck with it. > > > > > > So.. Markers and References, or Alleles and References, are both many > to > > > many relationships through the Reference_Assoc table. Is it possible to > > > represent this in SQL Alchemy mappings, where you could set up a > mapping to > > > have Marker.references as a property (and the backref > Reference.markers)? It > > > would be really nice to be able to define this relationship in an easy > way, > > > because we have over 30 different types of objects that can be > associated > > > this way. > > > > > > P.S. I have been using the declarative method of defining tables, but > I can > > > go a different route if that won't work. > > > > > > > For the read-only case this should be fairly simple - you can define > > whatever join criteria you want when creating a relationship. See the > > examples at > http://docs.sqlalchemy.org/en/rel_0_8/orm/relationships.html#specifying-alternate-join-conditions > . > > > > If you decide in the future to make this a writable interface as well, > > I suspect you will have to work a bit harder. You'll probably want to > > map a class to the Reference_Assoc table (optionally using > > single-table inheritance so that you have a subclass per type_key) > > > > 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 http://groups.google.com/group/sqlalchemy?hl=en. > > For more options, visit https://groups.google.com/groups/opt_out. > > > > > > -- > 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 http://groups.google.com/group/sqlalchemy?hl=en. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- 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 http://groups.google.com/group/sqlalchemy?hl=en. For more options, visit https://groups.google.com/groups/opt_out.