On 7/1/14, 4:54 PM, Ken Lareau wrote: > Related to one of my recent posted threads here, I'm recalling a certain > conversation at PyCon where I was mentioning how a friend would define > a many-to-many relationship by defining a relationship on both declarative > classes involved, each pointing to the other, and the look of abject > horror > I received gave a good indication that this is very often not a good > thing. > However, I've run into a situation where this has proven useful: > > class Deployment(Base): > __tablename__ = 'deployments' > > id = Column(u'DeploymentID', INTEGER(), primary_key=True) > package_id = Column( > INTEGER(), > ForeignKey('packages.package_id', ondelete='cascade'), > nullable=False > ) > > package = relationship('Package') > > > class Package(Base): > __tablename__ = 'packages' > > id = Column(u'package_id', INTEGER(), primary_key=True) > pkg_name = Column(String(length=255), nullable=False) > version = Column(String(length=63), nullable=False) > revision = Column(String(length=63), nullable=False) > > deployments = relationship('Deployment') > > In this case, most of the time I'm looking to determine which deployments > a given package belongs to, but there are times when I have a given > deployment and am curious as to what package(s) are related to it, and > unless I'm misunderstanding something (which I won't rule out I could > be), a backref won't easily help in this instance. I'm not actually familiar with what you mean by "a backref won't easily help". Above, Package.deployments and Deployment.package refer to the same linkage between the two classes, just in different directions. A backref above is equivalent to what you have, plus:
class Deployment(Base): # ... package = relationship("Package", back_populates='deployments') class Package(Base): # ... deployments = relationship("Deployment", back_populates='package') the importance of back_populates (or backref, essentially a shortcut to the same thing) is mostly in how the collection or attribute responds to in-Python changes and to a lesser (but sometimes important) extent how the attributes are treated during the flush process. The two relationships don't have to be related to each other at the Python level like this, but there's usually no reason to omit this information as it only allows the ORM to better keep the two sides in sync. > > Of course, one of the gotchas in using this (and we did hit it in one of > our queries) is if not careful, one can trigger a nice 'maximum recursion > depth exceeded' exception (in our particular case, a 'joinedload' within > the query was able to resolve that issue) and I'm sure there other poten- > tial "gotchas", so I guess this leads back to the main question at hand: I don't doubt that this can happen but I'm not familiar at the moment what the nature of this recursion issue would be. > Are there times when using "reciprocal" relationships is okay, and are > there certain things that should be done to mitigate potential issues that > can be caused by doing so, or are there better ways to accomplish the > same thing? It's not clear to me what the "thing" is that you want to accomplish here. If it's just, you want to set up the two relationships as explicit code for readability, that's great, use back_populates. This is probably how apps should be doing it anyway, in the early SQLAlchemy days there was a lot of pressure to not require too much boilerplate, hence "backref". These days, the community has moved well past the whole notion of "super minimal declaration / magic == good", thankfully. -- 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. For more options, visit https://groups.google.com/d/optout.