[sqlalchemy] Regarding the use of reciprocal relationships

2014-07-01 Thread Ken Lareau
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.

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:

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?

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


Re: [sqlalchemy] Regarding the use of reciprocal relationships

2014-07-01 Thread Mike Bayer

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.


Re: [sqlalchemy] Regarding the use of reciprocal relationships

2014-07-01 Thread Ken Lareau
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.


Re: [sqlalchemy] Regarding the use of reciprocal relationships

2014-07-01 Thread Jonathan Vanasco


   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.


Personally, I would LOVE a strict config setting that would raise an 
exception if both sides of a relationship weren't explicitly defined.  

This is convenient...

class Users(Base):
addresses = relationship(Addresses, backref=users)

class Addresses(Base):
pass
  
But when you're tracking down bugs and dealing with code that probably 
(honestly) should have failed a peer review, that can make all the 
difference.

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