At the moment I've moved to other features, but I should be back to this 
somewhere in the near future. I will let you know the results.

I really appreciate your time, thanks again.

Best,

Am Donnerstag, 3. Mai 2018 10:10:47 UTC-3 schrieb Mike Bayer:
>
> On Thu, May 3, 2018 at 7:39 AM, Diego Quintana <daqui...@gmail.com 
> <javascript:>> wrote: 
> > Thanks again for your reply 
> > 
> >> at the core is that when you remove a child from the parent in the 
> >> _remove_pets event, you want to prevent the _remove_children() event 
> >> from actually happening, I think. 
> > 
> > 
> > Yes, since it is a different usage case or flavour. I was trying to pass 
> > kwargs to the event listener directly, but it does not work. 
> > 
> >> If I remove a pet from a parent, then we remove the child from the 
> >> parent, and *only* that pet.  we dont remove other pets that might be 
> >> associated with that child. 
> > 
> > 
> > Correct, this would be case A and the idea behind it is that, if a User 
> has 
> > *access* to a Child, it should also have access to all of the Child's 
> pets. 
> > If for some reason Parent does not have access to all of them, means it 
> does 
> > not have access to the Child either. 
> > 
> > Removing a pet that has a Child that is also present in user.children 
> should 
> > trigger this, leaving the parent with, as you say, only pets minus the 
> one 
> > that was removed. It would also remove the child from the 
> parent/children 
> > relationship in the association table. 
> > 
> >> if I remove a child from the parent, then we remove *all* pets 
> >> associated with the child from that parent. 
> > 
> > 
> > Correct, and this would be case B 
> > 
> >> This seems like it's a contradiction.  I have parent p1, not referring 
> >> to child c1, but it refers to pet p1 which *does* refer to child c1, 
> >> and that is valid.     There's basically two flavors of "remove child 
> >> from parent", is that right? 
> > 
> > 
> > Yes, both relationships -parent/pet and parent/child- are not seeing 
> each 
> > other, and the only binding is 
> > their relationship between child and pets. 
> > 
> > Thus, the two flavors are depending on where is that listener being 
> called 
> > from. For the case A, this is called inside the if statement in 
> > _remove_pets. Outside of this it should be always case B. 
> > 
> >> I tried to work on an implementation here which would also have to be 
> >> extremely clever but I realized I don't actually understand what this 
> >> is supposed to do.  if "remove child from parent" has two different 
> >> flavors then there needs to be all kinds of trickery to protect the 
> >> events from each other. 
> > 
> > 
> > I understand that it requires a lot of fiddling. I was trying to pass 
> kwargs 
> > to the listener directly, and parse them inside the other listener, but 
> the 
> > other listener is not receiving them. I was seeing this is on purpose 
> here , 
> > since accepting kwargs would pollute the API. Perhaps a custom event 
> > implementation? 
>
> I slowly realized it looked like you hoped that flag would pass 
> through but there's too many layers of indirection for it to work that 
> way.  the main complication here is that those "dynamic" relationships 
> require that a query runs for everything, which means everything has 
> to be in the database, which means it flushes the session very 
> aggressively (and also disabling the flush, another thing I tried, 
> means it doesn't read the contents of the collections accurately), and 
> all of that makes an already tricky operation nearly impossible 
> without it barreling into itself. 
>
> If you are committed to using the "dynamic" relationships, you can 
> always rely on emitting SQL to read from those association tables, and 
> there's a completely unorthodox way to do this which would be way more 
> efficient in most cases, and is extremely simple, just emit the DELETE 
> statements: 
>
> from sqlalchemy.orm import object_session 
>
> @sa.event.listens_for(Parent.children, 'remove') 
> def _remove_children(parent, child, initiator, *args, **kwargs): 
>     object_session(parent).execute( 
>         "delete from parents_pets_relationship where " 
>         "parent_id=:parent_id and pet_id=:pet_id", 
>         [ 
>             {"parent_id": parent.id, "pet_id": pet.id} 
>             for pet in child.pets 
>         ] 
>     ) 
>
>
> @sa.event.listens_for(Parent.pets, 'remove') 
> def _remove_pets(parent, pet, initiator, *args, **kwargs): 
>     object_session(parent).execute( 
>         "delete from parents_children_relationship where " 
>         "parent_id=:parent_id and child_id=:child_id", 
>         {"parent_id": parent.id, "child_id": pet.child.id} 
>     ) 
>
> I added a second test for the other case and this works as far as I've 
> gotten it.  since we are only dealing with these standalone 
> association tables the above is pretty simple, and now you only emit 
> one query (albeit a DML query, not a SELECT) rather than lots of 
> SELECT statements.       The above is at least very simple to work 
> with since the ORM has no involvement past getting you those events. 
>
> if the above does what you need then it's probably worth doing that way. 
>
>
>
> > 
> > Thanks again for your time 
> > 
> > 
> > 
> > Diego Alexandro Quintana Valenzuela 
> > Ingeniero Civil Electricista 
> > Universidad de la Frontera - Chile 
> > +56 9 7965 3455 
> > 
> > IEEE PES & CIS Member 
> > diego.q...@ieee.org <javascript:> 
> > LinkedIn 
> > https://www.linkedin.com/in/diego-quintana-valenzuela/ 
> > 
> > 2018-05-02 18:46 GMT-03:00 Mike Bayer <mik...@zzzcomputing.com 
> <javascript:>>: 
> >> 
> >> On Wed, May 2, 2018 at 12:22 PM, Diego Quintana <daqui...@gmail.com 
> <javascript:>> 
> >> wrote: 
> >> > Hello, thanks again for your help. I'm not sure I understand what you 
> >> > said 
> >> > totally, and I believe this is the most simple MCVE I can provide. 
> >> > 
> >> > My local tests use postgresql, but I'm setting an in-memory sqlite3 
> >> > engine 
> >> > here. I'm not fond of the differences between two backends, but the 
> >> > tests 
> >> > run without problems. 
> >> 
> >> So this is great, and shows the problem.  but what you are trying to 
> >> do here is deeply complicated.    I was going to just type out 
> >> everything I did to figure this out but this was way too long a 
> >> process. 
> >> 
> >> at the core is that when you remove a child from the parent in the 
> >> _remove_pets event, you want to prevent the _remove_children() event 
> >> from actually happening, I think. 
> >> 
> >> If I remove a pet from a parent, then we remove the child from the 
> >> parent, and *only* that pet.  we dont remove other pets that might be 
> >> associated with that child. 
> >> 
> >> if I remove a child from the parent, then we remove *all* pets 
> >> associated with the child from that parent. 
> >> 
> >> This seems like it's a contradiction.  I have parent p1, not referring 
> >> to child c1, but it refers to pet p1 which *does* refer to child c1, 
> >> and that is valid.     There's basically two flavors of "remove child 
> >> from parent", is that right? 
> >> 
> >> I tried to work on an implementation here which would also have to be 
> >> extremely clever but I realized I don't actually understand what this 
> >> is supposed to do.  if "remove child from parent" has two different 
> >> flavors then there needs to be all kinds of trickery to protect the 
> >> events from each other. 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> > import sqlalchemy as sa 
> >> > from sqlalchemy.ext.declarative import declarative_base 
> >> > 
> >> > Base = declarative_base() 
> >> > 
> >> > # many to many relationship between parents and children 
> >> > parents_children_relationship = 
> >> > sa.Table('parents_children_relationship', 
> >> >     Base.metadata, 
> >> >     sa.Column('parent_id', sa.Integer, sa.ForeignKey('parents.id')), 
> >> >     sa.Column('child_id', sa.Integer, sa.ForeignKey('children.id')), 
> >> >     sa.UniqueConstraint('parent_id', 'child_id')) 
> >> > 
> >> > # many to many relationship between User and Pet 
> >> > parents_pets_relationship = sa.Table('parents_pets_relationship', 
> >> >     Base.metadata, 
> >> >     sa.Column('parent_id', sa.Integer, sa.ForeignKey('parents.id')), 
> >> >     sa.Column('pet_id', sa.Integer, sa.ForeignKey('pets.id')), 
> >> >     sa.UniqueConstraint('parent_id', 'pet_id')) 
> >> > 
> >> > class Parent(Base): 
> >> >     __tablename__ = 'parents' 
> >> > 
> >> >     id = sa.Column(sa.Integer, primary_key=True) 
> >> >     name = sa.Column(sa.String(64)) 
> >> > 
> >> >     # many to many relationship between parent and children 
> >> >     # my case allows for a children to have many parents. Don't ask. 
> >> >     children = sa.orm.relationship('Child', 
> >> >                             secondary=parents_children_relationship, 
> >> >                             backref=sa.orm.backref('parents', 
> >> > lazy='dynamic'), 
> >> >                             lazy='dynamic') 
> >> > 
> >> >     # many to many relationship between parents and pets 
> >> >     pets = sa.orm.relationship('Pet', 
> >> >                             secondary=parents_pets_relationship, 
> >> >                             backref=sa.orm.backref('parents', 
> >> > lazy='dynamic'), # 
> >> >                             lazy='dynamic') 
> >> > 
> >> > 
> >> >     def __repr__(self): 
> >> >         return '<Parent (name=%r)>' % (self.name) 
> >> > 
> >> > class Child(Base): 
> >> >     __tablename__ = 'children' 
> >> >     id = sa.Column(sa.Integer, primary_key=True) 
> >> >     name = sa.Column(sa.String(64)) 
> >> >     # parents = <backref relationship with User model> 
> >> > 
> >> >     # one to many relationship with pets 
> >> >     pets = sa.orm.relationship('Pet', backref='child', 
> lazy='dynamic') 
> >> > 
> >> >     def __repr__(self): 
> >> >         return '<Child (name=%r)>' % (self.name) 
> >> > 
> >> > class Pet(Base): 
> >> >     __tablename__ = 'pets' 
> >> >     id = sa.Column(sa.Integer, primary_key=True) 
> >> >     name = sa.Column(sa.String(64)) 
> >> >     # child = backref relationship with cities 
> >> >     child_id = sa.Column(sa.Integer, sa.ForeignKey('children.id'), 
> >> > nullable=True) 
> >> >     # parents = <relationship backref from User> 
> >> > 
> >> >     def __repr__(self): 
> >> >         return '<Pet (name=%r)>' % (self.name) 
> >> > 
> >> > 
> >> > 
> >> > @sa.event.listens_for(Parent.children, 'append') 
> >> > def _append_children(parent, child, initiator): 
> >> >     """ 
> >> >     If a new child is appended to the parent, this listener 
> >> >     will also add the pets bound to the child being bound to the 
> parent. 
> >> >     """ 
> >> >     # appends also the pets bound to the child that the 
> >> >     # parent is being appended to 
> >> >     parent.pets.extend(child.pets.all()) 
> >> > 
> >> > @sa.event.listens_for(Parent.children, 'remove') 
> >> > def _remove_children(parent, child, initiator, *args, **kwargs): 
> >> >     """ 
> >> >     If a child is removed from the parent, this listener 
> >> >     will also remove only remove_single_pet --> <Pet> 
> >> >     """ 
> >> > 
> >> >     remove_single_pet = kwargs.get('remove_single_pet', None) 
> >> > 
> >> >     if remove_single_pet is not None: 
> >> >         parent.pets.remove(remove_single_pet) 
> >> >     else: # removes every pet 
> >> >         for pet in child.pets: 
> >> >             parent.pets.remove(pet) 
> >> > 
> >> > @sa.event.listens_for(Parent.pets, 'remove') 
> >> > def _remove_pets(parent, pet, initiator, *args, **kwargs): 
> >> >     """ 
> >> >     If a pet is removed from the parent, and the parent also is 
> related 
> >> >     to the child that has access to that pet, then 
> >> > 
> >> >     * removes relationship with the child, and 
> >> >     * keeps relationship with the remaining pets, except the one that 
> >> > was 
> >> > removed 
> >> >     """ 
> >> > 
> >> >     if pet.child in parent.children.all(): 
> >> >         remove_single_pet = pet 
> >> >         _remove_children(parent, pet.child, initiator, 
> >> > remove_single_pet) 
> >> > 
> >> > 
> >> > #### test ### 
> >> > 
> >> > import unittest 
> >> > from sqlalchemy import create_engine 
> >> > from sqlalchemy.orm import sessionmaker 
> >> > 
> >> > class BasicTestModelCase(unittest.TestCase): 
> >> > 
> >> >     def setUp(self): 
> >> >         e = create_engine("sqlite://", echo=True) 
> >> >         Base.metadata.create_all(e) 
> >> > 
> >> >         Session = sessionmaker(bind=e) 
> >> >         self.session = Session() 
> >> > 
> >> > 
> >> >     def tearDown(self): 
> >> >         # Base.metadata.drop_all() 
> >> >         pass 
> >> > 
> >> >     def test_child_pet_relationship_on_parents_combined(self): 
> >> >         """ 
> >> >         Test that a parent can be hold children and pets that don't 
> >> >         belong necessary to the child, given the behaviour tested in 
> the 
> >> >         previous test. 
> >> >         """ 
> >> > 
> >> >         # create new parent 
> >> >         test_parent = Parent(name='test_parent') 
> >> > 
> >> >         child1 = Child(id=1, 
> >> >                         name='FakeChild1') 
> >> > 
> >> >         child2 = Child(id=2, 
> >> >                         name='FakeChild2') 
> >> > 
> >> >         pet1 = Pet(id=1, 
> >> >                     name='FakePet1', 
> >> >                     child_id=1) 
> >> > 
> >> >         pet2 = Pet(id=2, 
> >> >                     name='FakePet2', 
> >> >                     child_id=2) 
> >> > 
> >> >         pet3 = Pet(id=3, 
> >> >                     name='FakePet3', 
> >> >                     child_id=1) 
> >> > 
> >> >         self.session.add(test_parent) 
> >> >         self.session.add(child1) 
> >> >         self.session.add(child2) 
> >> >         self.session.add(pet1) 
> >> >         self.session.add(pet2) 
> >> >         self.session.add(pet3) 
> >> >         self.session.commit() 
> >> > 
> >> >         # add parent to the child 
> >> >         child1.parents.append(test_parent) 
> >> >         self.session.add(child1) 
> >> >         self.session.commit() 
> >> > 
> >> >         # add parent to the child 
> >> >         pet2.parents.append(test_parent) 
> >> > 
> >> >         # persist changes in the db 
> >> >         self.session.add(pet2) 
> >> >         self.session.commit() 
> >> > 
> >> >         print(test_parent.pets.all()) 
> >> >         print(child2.pets.all()) 
> >> > 
> >> >         # check that previous relationships are intact 
> >> >         self.assertTrue(child1.pets.all() == [pet1, pet3]) 
> >> >         self.assertTrue(child2.pets.all() == [pet2]) 
> >> > 
> >> >         # resultant elements should be only child1, its pets and the 
> >> > single 
> >> > Pet 
> >> >         self.assertTrue(test_parent.children.all() == [child1]) 
> >> >         self.assertTrue(test_parent.pets.all() == [pet1, pet2, pet3]) 
> >> > 
> >> >         # remove child from parent 
> >> >         pet3.parents.remove(test_parent) ## ERROR here 
> >> > 
> >> >         # resultant elements should be remaining pets, and no child 
> >> >         self.assertTrue(test_parent.children.all() == []) 
> >> >         self.assertTrue(test_parent.pets.all() == [pet1, pet2]) # 
> pet2 
> >> > was 
> >> > not touched, 
> >> >                                                                 # but 
> >> > pet1 
> >> > should remain since only 
> >> >                                                                 # 
> pet3 
> >> > was 
> >> > removed 
> >> >                                                                 # 
> child1 
> >> > should be also removed since 
> >> >                                                                 # 
> >> > relationship is unbalanced, i.e. 
> >> >                                                                 # 
> user 
> >> > can't 
> >> > have access to a child if it 
> >> >                                                                 # 
> does 
> >> > not 
> >> > have access to all of the child's pets 
> >> > 
> >> > if __name__ == '__main__': 
> >> >     # run tests 
> >> >     unittest.main() 
> >> > 
> >> > Am Mittwoch, 2. Mai 2018 11:40:14 UTC-3 schrieb Mike Bayer: 
> >> >> 
> >> >> On Wed, May 2, 2018 at 10:14 AM, Diego Quintana <daqui...@gmail.com> 
>
> >> >> wrote: 
> >> >> > This worked. 
> >> >> > 
> >> >> > I'm trying to achieve some rather tricky behaviour, where 
> >> >> > 
> >> >> > Adding a children to some parent will also add the child's pets to 
> >> >> > the 
> >> >> > parent 
> >> >> > Removing a children from some parent will also remove every 
> current 
> >> >> > relationship that the Parent has with such pet 
> >> >> > If upon removal of a pet from a Parent, there is a Pet.child that 
> is 
> >> >> > also in 
> >> >> > Parent.children, 
> >> >> > 
> >> >> > remove that Child from Parent, but keep existing relationships in 
> >> >> > Parent.pets except the pet that is being removed 
> >> >> > else only remove the pet from the parent 
> >> >> > 
> >> >> > 
> >> >> > Some code I'm using for this is 
> >> >> > 
> >> >> > @db.event.listens_for(Parent.children, 'append') 
> >> >> > def _append_children(parent, child, initiator): 
> >> >> >     """ 
> >> >> >     If a new child is appended to the parent, this listener 
> >> >> >     will also add the pets bound to the child being bound to the 
> >> >> > parent. 
> >> >> >     """ 
> >> >> >     # appends also the pets bound to the child that the 
> >> >> >     # parent is being appended to 
> >> >> >     parent.pets.extend(child.pets.all()) 
> >> >> > 
> >> >> > @db.event.listens_for(Parent.children, 'remove') 
> >> >> > def _remove_children(parent, child, initiator, *args, **kwargs): 
> >> >> >     """ 
> >> >> >     If a child is removed from the parent, this listener 
> >> >> >     will also remove only remove_single_pet --> <Pet> 
> >> >> >     """ 
> >> >> > 
> >> >> >     remove_single_pet = kwargs.get('remove_single_pet', None) 
> >> >> > 
> >> >> >     if remove_single_pet is not None: 
> >> >> >         parent.pets.remove(remove_single_pet) 
> >> >> >     else: # removes every pet 
> >> >> >         for pet in child.pets: 
> >> >> >             parent.pets.remove(pet) 
> >> >> > 
> >> >> > 
> >> >> > @db.event.listens_for(Parent.pets, 'remove') 
> >> >> > def _remove_pets(parent, pet, initiator, *args, **kwargs): 
> >> >> >     """ 
> >> >> >     If a pet is removed from the parent, and the parent also is 
> >> >> > related 
> >> >> >     to the child that has access to that pet, then 
> >> >> > 
> >> >> >     * removes relationship with the child, and 
> >> >> >     * keeps relationship with the remaining pets, except the one 
> that 
> >> >> > was 
> >> >> > removed 
> >> >> >     """ 
> >> >> > 
> >> >> >     if pet.child in parent.children.all(): 
> >> >> >         remove_single_pet = pet 
> >> >> >         _remove_children(parent, pet.child, initiator, 
> >> >> > remove_single_pet) 
> >> >> > 
> >> >> > 
> >> >> > #### test.py 
> >> >> > 
> >> >> >  def test_child_pet_relationship_on_parents(self): 
> >> >> > 
> >> >> > 
> >> >> >         # create new parent 
> >> >> >         test_parent = Parent(name='test_parent') 
> >> >> > 
> >> >> >         # commit parent to the database 
> >> >> >         db.session.add(test_parent) 
> >> >> >         db.session.commit() 
> >> >> > 
> >> >> >         child1 = Child(id=1, 
> >> >> >                      name='FakeChild1') 
> >> >> > 
> >> >> >         child2 = Child(id=2, 
> >> >> >                      name='FakeChild2') 
> >> >> > 
> >> >> >         pet1 = Pet(id=1, 
> >> >> >                    name='FakePet1', 
> >> >> >                    child_id=1) 
> >> >> > 
> >> >> >         pet2 = Pet(id=2, 
> >> >> >                    name='FakePet2', 
> >> >> >                    child_id=2) 
> >> >> > 
> >> >> >         pet3 = Pet(id=3, 
> >> >> >                    name='FakePet3', 
> >> >> >                    child_id=1) 
> >> >> > 
> >> >> >         db.session.add(child1) 
> >> >> >         db.session.add(child2) 
> >> >> >         db.session.add(pet1) 
> >> >> >         db.session.add(pet2) 
> >> >> >         db.session.add(pet3) 
> >> >> > 
> >> >> >         db.session.commit() 
> >> >> > 
> >> >> >         # add parent to the child 
> >> >> >         child1.parents.append(test_parent) 
> >> >> >         # add parent to the child 
> >> >> >         pet2.parents.append(test_parent) 
> >> >> > 
> >> >> >         # persist changes in the db 
> >> >> >         db.session.add(child1) 
> >> >> >         db.session.add(pet2) 
> >> >> >         db.session.commit() 
> >> >> > 
> >> >> >         # check that previous relationships are intact 
> >> >> >         self.assertTrue(child1.pets.all() == [pet1, pet3]) 
> >> >> >         self.assertTrue(child2.pets.all() == [pet2]) 
> >> >> > 
> >> >> >         # resultant elements should be only child1, its pets and 
> the 
> >> >> > single 
> >> >> > Pet 
> >> >> >         self.assertTrue(test_parent.children.all() == [child1]) 
> >> >> >         self.assertTrue(test_parent.pets.all() == [pet1, pet2, 
> pet3]) 
> >> >> > 
> >> >> >         # remove child from parent 
> >> >> >         pet3.parents.remove(test_parent) 
> >> >> > 
> >> >> >         # resultant elements should be remaining pets, and no 
> child 
> >> >> >         self.assertTrue(test_parent.children.all() == []) 
> >> >> >         self.assertTrue(test_parent.pets.all() == [pet1, pet2]) # 
> >> >> > pet2 
> >> >> > was 
> >> >> > not touched, 
> >> >> >                                                                 # 
> but 
> >> >> > pet1 
> >> >> > should remain since only 
> >> >> >                                                                 # 
> >> >> > pet3 
> >> >> > was 
> >> >> > removed 
> >> >> >                                                                 # 
> >> >> > child1 
> >> >> > should be also removed since 
> >> >> >                                                                 # 
> >> >> > relationship is unbalanced, i.e. 
> >> >> >                                                                 # 
> >> >> > user 
> >> >> > can't 
> >> >> > have access to a child if it 
> >> >> >                                                                 # 
> >> >> > does 
> >> >> > not 
> >> >> > have access to all of the child's pets 
> >> >> > 
> >> >> > 
> >> >> > 
> >> >> > I'm having errors 
> >> >> > 
> >> >> > sqlalchemy.orm.exc.StaleDataError: DELETE statement on table 
> >> >> > 'parent_pets_relationship' expected to delete 1 row(s); Only 0 
> were 
> >> >> > matched. 
> >> >> 
> >> >> it looks like you have an explicit association mapping on the 
> >> >> secondary table as described in the green box in the section 
> >> >> 
> >> >> 
> >> >> 
> https://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#association-object,
>  
>
> >> >> but I dont' have your complete mappings so I can't say for sure, 
> you'd 
> >> >> need to provide a complete MCVE. 
> >> >> 
> >> >> 
> >> >> 
> >> >> 
> >> >> > 
> >> >> > and the logger says nothing much. I suspect I'm falling into some 
> >> >> > weird 
> >> >> > recursion, calling the listener from another listener, where the 
> >> >> > second 
> >> >> > call 
> >> >> > can't find something that was already deleted. 
> >> >> > 
> >> >> > This might be a long shot, but I'm hoping this pattern might be 
> >> >> > solved 
> >> >> > already. 
> >> >> > 
> >> >> > 
> >> >> > Am Donnerstag, 26. April 2018 13:00:45 UTC-3 schrieb Mike Bayer: 
> >> >> >> 
> >> >> >> On Thu, Apr 26, 2018 at 11:04 AM, Diego Quintana 
> >> >> >> <daqui...@gmail.com> 
> >> >> >> wrote: 
> >> >> >> > Hello. 
> >> >> >> > 
> >> >> >> > Say I have three tables in a declarative fashion, `Parent`, 
> >> >> >> > `Child`, 
> >> >> >> > and 
> >> >> >> > `Pet`, in such way that 
> >> >> >> > 
> >> >> >> > * `Parent` has a many-to-many relationship with both `Child` 
> and 
> >> >> >> > `Pet`, 
> >> >> >> > meaning that a Parent can own a Child and its pets, and also a 
> Pet 
> >> >> >> > without 
> >> >> >> > its Child. 
> >> >> >> > * `Child` has a one-to-many relationship with `Pet` 
> >> >> >> > 
> >> >> >> > The code for them is (using Flask-SQLAlchemy, although I 
> believe 
> >> >> >> > the 
> >> >> >> > solution lives in the realm of SQLAlchemy rather than in 
> Flask). 
> >> >> >> > 
> >> >> >> >     class Parent(db.Model): 
> >> >> >> >         __tablename__ = 'parents' 
> >> >> >> > 
> >> >> >> >         id = db.Column(db.Integer, primary_key=True) 
> >> >> >> >         name = db.Column(db.String(64)) 
> >> >> >> > 
> >> >> >> >         # many to many relationship between parent and children 
> >> >> >> >         # my case allows for a children to have many parents. 
> >> >> >> > Don't 
> >> >> >> > ask. 
> >> >> >> >         children = db.relationship('Child', 
> >> >> >> > 
> >> >> >> > secondary=parents_children_relationship, 
> >> >> >> >                                backref=db.backref('parents', 
> >> >> >> > lazy='dynamic'), 
> >> >> >> >                                lazy='dynamic') 
> >> >> >> > 
> >> >> >> >         # many to many relationship between parents and pets 
> >> >> >> >         pets = db.relationship('Pet', 
> >> >> >> > 
> >> >> >> > secondary=users_pets_relationship, 
> >> >> >> >                                  backref=db.backref('parents', 
> >> >> >> > lazy='dynamic'), # 
> >> >> >> >                                  lazy='dynamic') 
> >> >> >> > 
> >> >> >> >     # many to many relationship between parents and children 
> >> >> >> >     parents_children_relationship = 
> >> >> >> > db.Table('parents_children_relationship', 
> >> >> >> >         db.Column('parent_id', db.Integer, 
> >> >> >> > db.ForeignKey('parents.id')), 
> >> >> >> >         db.Column('child_id', db.Integer, 
> >> >> >> > db.ForeignKey('children.id')), 
> >> >> >> >         UniqueConstraint('parent_id', 'child_id')) 
> >> >> >> > 
> >> >> >> >     # many to many relationship between User and Pet 
> >> >> >> >     users_pets_relationship = 
> db.Table('users_pets_relationship', 
> >> >> >> >         db.Column('parent_id', db.Integer, 
> >> >> >> > db.ForeignKey('parents.id')), 
> >> >> >> >         db.Column('pet_id', db.Integer, db.ForeignKey('pets.id')), 
>
> >> >> >> >         UniqueConstraint('parent_id', 'pet_id')) 
> >> >> >> > 
> >> >> >> >     class Child(db.Model): 
> >> >> >> >         __tablename__ = 'children' 
> >> >> >> >         id = db.Column(db.Integer, primary_key=True) 
> >> >> >> >         name = db.Column(db.String(64)) 
> >> >> >> >         # parents = <backref relationship with User model> 
> >> >> >> > 
> >> >> >> >         # one to many relationship with pets 
> >> >> >> >         pets = db.relationship('Pet', backref='child', 
> >> >> >> > lazy='dynamic') 
> >> >> >> > 
> >> >> >> > 
> >> >> >> >     class Pet(db.Model): 
> >> >> >> >         __tablename__ = 'pets' 
> >> >> >> >         id = db.Column(db.Integer, primary_key=True) 
> >> >> >> >         name = db.Column(db.String(64)) 
> >> >> >> >         # child = backref relationship with cities 
> >> >> >> >         child_id = db.Column(db.Integer, 
> >> >> >> > db.ForeignKey('children.id'), 
> >> >> >> > nullable=True) 
> >> >> >> >         # parents = <relationship backref from User> 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > I would like to do something like this 
> >> >> >> > 
> >> >> >> >     parent_a = Parent() 
> >> >> >> >     child_a = Child() 
> >> >> >> >     pet_a = Pet() 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > I can then do this 
> >> >> >> > 
> >> >> >> >     parent_a.children.append(child_a) 
> >> >> >> >     # commit/persist data 
> >> >> >> >     parent_a.children.all() # [child_a] 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > I would like to achieve something like this 
> >> >> >> > 
> >> >> >> >     child_a.pets.append(pet_a) 
> >> >> >> >     parent_a.children.append(child_a) 
> >> >> >> >     # commit/persist data 
> >> >> >> >     parent_a.children.all() # [child_a] 
> >> >> >> >     parent_a.pets.all() # [pet_a], because pet_a gets 
> >> >> >> >                         # automatically added to parent using 
> some 
> >> >> >> > sorcery 
> >> >> >> >                         # like for child in 
> >> >> >> > parent_a.children.all(): 
> >> >> >> >                         #     
> parent.pets.append(child.pets.all()) 
> >> >> >> >                         # or something like that. 
> >> >> >> > 
> >> >> >> > I can achieve this with a method in the Parent object like 
> >> >> >> > add_child_and_its_pets(), but I would like to override the way 
> >> >> >> > relationship 
> >> >> >> > works, so I don't need to override other modules that may 
> benefit 
> >> >> >> > from 
> >> >> >> > this 
> >> >> >> > behaviour, like Flask-Admin for instance. 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > Basically how should I override the backref.append method or 
> the 
> >> >> >> > relationship.append method to also append other objects from 
> other 
> >> >> >> > relationships at call time i.e. on the python side? How should 
> I 
> >> >> >> > override 
> >> >> >> > the remove methods as well? 
> >> >> >> 
> >> >> >> this seems like coordination of two separate relationships, so 
> use 
> >> >> >> attribute events for that, 
> >> >> >> 
> >> >> >> 
> >> >> >> 
> >> >> >> 
> http://docs.sqlalchemy.org/en/latest/orm/events.html?highlight=attributeevent#sqlalchemy.orm.events.AttributeEvents
>  
> >> >> >> : 
> >> >> >> 
> >> >> >> @event.listens_for(Parent.children, "append") 
> >> >> >> def _append_pets(parent, child, initiator): 
> >> >> >>     parent.pets.extend(child.pets)   # or whatever it is you need 
> >> >> >> 
> >> >> >> you would need to look at the "append" and "remove" events. 
> >> >> >> 
> >> >> >> 
> >> >> >> 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > I have also posted this question in Stack Overflow, in case it 
> >> >> >> > means 
> >> >> >> > something. 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > Best! 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > -- 
> >> >> >> > SQLAlchemy - 
> >> >> >> > The Python SQL Toolkit and Object Relational Mapper 
> >> >> >> > 
> >> >> >> > http://www.sqlalchemy.org/ 
> >> >> >> > 
> >> >> >> > To post example code, please provide an MCVE: Minimal, 
> Complete, 
> >> >> >> > and 
> >> >> >> > Verifiable Example. See http://stackoverflow.com/help/mcve for 
> a 
> >> >> >> > full 
> >> >> >> > description. 
> >> >> >> > --- 
> >> >> >> > 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+...@googlegroups.com. 
> >> >> >> > To post to this group, send email to sqlal...@googlegroups.com. 
>
> >> >> >> > Visit this group at https://groups.google.com/group/sqlalchemy. 
>
> >> >> >> > For more options, visit https://groups.google.com/d/optout. 
> >> >> > 
> >> >> > -- 
> >> >> > SQLAlchemy - 
> >> >> > The Python SQL Toolkit and Object Relational Mapper 
> >> >> > 
> >> >> > http://www.sqlalchemy.org/ 
> >> >> > 
> >> >> > To post example code, please provide an MCVE: Minimal, Complete, 
> and 
> >> >> > Verifiable Example. See http://stackoverflow.com/help/mcve for a 
> full 
> >> >> > description. 
> >> >> > --- 
> >> >> > 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+...@googlegroups.com. 
> >> >> > To post to this group, send email to sqlal...@googlegroups.com. 
> >> >> > Visit this group at https://groups.google.com/group/sqlalchemy. 
> >> >> > For more options, visit https://groups.google.com/d/optout. 
> >> > 
> >> > -- 
> >> > SQLAlchemy - 
> >> > The Python SQL Toolkit and Object Relational Mapper 
> >> > 
> >> > http://www.sqlalchemy.org/ 
> >> > 
> >> > To post example code, please provide an MCVE: Minimal, Complete, and 
> >> > Verifiable Example. See http://stackoverflow.com/help/mcve for a 
> full 
> >> > description. 
> >> > --- 
> >> > 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+...@googlegroups.com <javascript:>. 
> >> > To post to this group, send email to sqlal...@googlegroups.com 
> <javascript:>. 
> >> > Visit this group at https://groups.google.com/group/sqlalchemy. 
> >> > For more options, visit https://groups.google.com/d/optout. 
> >> 
> >> -- 
> >> SQLAlchemy - 
> >> The Python SQL Toolkit and Object Relational Mapper 
> >> 
> >> http://www.sqlalchemy.org/ 
> >> 
> >> To post example code, please provide an MCVE: Minimal, Complete, and 
> >> Verifiable Example.  See  http://stackoverflow.com/help/mcve for a 
> full 
> >> description. 
> >> --- 
> >> You received this message because you are subscribed to a topic in the 
> >> Google Groups "sqlalchemy" group. 
> >> To unsubscribe from this topic, visit 
> >> https://groups.google.com/d/topic/sqlalchemy/jgKgv5zQT7E/unsubscribe. 
> >> To unsubscribe from this group and all its topics, send an email to 
> >> sqlalchemy+...@googlegroups.com <javascript:>. 
> >> To post to this group, send email to sqlal...@googlegroups.com 
> <javascript:>. 
> >> Visit this group at https://groups.google.com/group/sqlalchemy. 
> >> For more options, visit https://groups.google.com/d/optout. 
> > 
> > 
> > -- 
> > SQLAlchemy - 
> > The Python SQL Toolkit and Object Relational Mapper 
> > 
> > http://www.sqlalchemy.org/ 
> > 
> > To post example code, please provide an MCVE: Minimal, Complete, and 
> > Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> > description. 
> > --- 
> > 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+...@googlegroups.com <javascript:>. 
> > To post to this group, send email to sqlal...@googlegroups.com 
> <javascript:>. 
> > Visit this group at https://groups.google.com/group/sqlalchemy. 
> > For more options, visit https://groups.google.com/d/optout. 
>

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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.

Reply via email to