On Tue, Jul 1, 2014 at 2:17 PM, Mike Bayer <mike...@zzzcomputing.com> wrote:
> > 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. > Oy, leave it to me to misinterpret once again (and I have read that part of the docs before, so I should have known better). For some reason I had in my head that the backref could only be used from the class that the relationship was defined on. :-/ > > > > 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. > Talking with my coworker again, I believe I may have misspoke on the 'joinedload' solving the issue (we used that for performance improvements I think), but it was while we were trying things out that we caused the recursion issue and sadly neither of us can remember exactly what trig- gered that! So please forget that part, my memory is terrible as of late. *smile* > 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. > We've gone ahead and utilized the 'back_populates' for this case, and I thank you for the assistance and clarification here! -- - Ken Lareau -- 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.