It was in fact a one liner, so you can go back to your original code if you use 
the latest 0.6 tip:

http://hg.sqlalchemy.org/sqlalchemy/archive/rel_0_6.tar.gz

thanks for the bug report !


On Dec 15, 2010, at 3:41 PM, Will Weaver wrote:

> Wow, this has been a problem for me for the past 3 or 4 days and took
> a while to get to that example.  Defining the backrefs or the
> relationships in the opposite direction did the job.  I had
> intentionally left out some of the backreffed relationships because I
> didn't need them for what I was working on, but it definitely is worth
> it to get this working.
> 
> Thanks a lot.
> 
> -Will
> 
> On Wed, Dec 15, 2010 at 2:45 PM, Michael Bayer <mike...@zzzcomputing.com> 
> wrote:
>> This is an interesting edge case and I can probably ensure that the 
>> dependency between Parent/Child is present in the unit of work even if there 
>> is no known linkage at the Child.parent level for the objects actually 
>> present - ticket #2002 is added for this.
>> 
>> In the meantime, the uow needs to be aware of the linkage between 
>> Parent->Child when flush occurs.   Adding a backref "children" to the parent 
>> relationship will do it, or ensuring that child.parent is accessed before 
>> emitting the flush will do it.     The usual way this kind of delete is 
>> performed is the "delete" cascade is added to the "children" backref, then 
>> the Parent is deleted alone, the deletes cascading to the Child objects 
>> naturally.
>> 
>> But this is a fun bug and I'll probably have a fix very soon, perhaps in 10 
>> minutes or maybe not.
>> 
>> 
>> 
>> 
>> On Dec 15, 2010, at 2:17 PM, Will wrote:
>> 
>>> """
>>> Hello,
>>> 
>>> I've been recently having a problem with sqlalchemy not flushing
>>> deletes in the proper order.  I've created a simple example for the
>>> problem that has been occuring.  I tried to run this using sqlite and
>>> it doesn't have any problems, it is only with Postgresql.
>>> 
>>> One thing of note is that if there is only one Child it doesn't seem
>>> to
>>> have a problem, only when there are multiple children.  Not sure if
>>> that makes a difference in the SQLAlchemy code.
>>> """
>>> 
>>> from sqlalchemy import create_engine
>>> from sqlalchemy.ext.declarative import declarative_base
>>> from sqlalchemy.orm import scoped_session, sessionmaker, relationship
>>> from sqlalchemy.schema import Column, ForeignKey
>>> from sqlalchemy.types import Integer
>>> 
>>> #engine = create_engine('sqlite:///')
>>> engine = create_engine('postgresql://test_runner@/testing_db')
>>> 
>>> Model = declarative_base()
>>> 
>>> 
>>> class Parent(Model):
>>>    __tablename__ = 'parents'
>>> 
>>>    id = Column(Integer, primary_key=True)
>>> 
>>> 
>>> class Child(Model):
>>>    __tablename__ = 'children'
>>> 
>>>    id = Column(Integer, primary_key=True)
>>>    parent_id = Column(Integer, ForeignKey('parents.id'),
>>>                       nullable=False)
>>>    parent = relationship('Parent')
>>> 
>>> 
>>> def begin():
>>>    """Begin transaction"""
>>>    #global transaction
>>>    #transaction = session.begin()
>>> 
>>>    session.begin()
>>> 
>>> 
>>> def commit():
>>>    """Commit transaction"""
>>>    #global transaction
>>>    #transaction.commit()
>>> 
>>>    session.commit()
>>> 
>>> 
>>> Model.metadata.create_all(engine)
>>> 
>>> parent = Parent()
>>> children = [Child(parent=parent), Child(parent=parent)]
>>> 
>>> Session = sessionmaker(bind=engine, autocommit=True)
>>> session = Session()
>>> 
>>> try:
>>>    session.bind.echo = True
>>> 
>>>    begin()
>>>    session.add_all(children)
>>>    session.add(parent)
>>>    commit()
>>> 
>>> 
>>>    begin()
>>>    for child in children:
>>>        session.delete(child)
>>>    session.delete(parent)
>>>    commit()
>>> 
>>>    session.bind.echo = False
>>> finally:
>>>    Model.metadata.drop_all(engine)
>>> 
>>> 
>>> """
>>> From running the script I have two different outputs because it seems
>>> to run the deletes in a random order so subsequent runs will behave
>>> differently.
>>> """
>>> 
>>> # Example Failed Run
>>> """
>>> 2010-12-15 13:45:05,050 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> BEGIN (implicit)
>>> 2010-12-15 13:45:05,051 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> INSERT INTO parents DEFAULT VALUES RETURNING parents.id
>>> 2010-12-15 13:45:05,051 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {}
>>> 2010-12-15 13:45:05,052 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> INSERT INTO children (parent_id) VALUES (%(parent_id)s) RETURNING
>>> children.id
>>> 2010-12-15 13:45:05,052 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {'parent_id': 1}
>>> 2010-12-15 13:45:05,053 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> INSERT INTO children (parent_id) VALUES (%(parent_id)s) RETURNING
>>> children.id
>>> 2010-12-15 13:45:05,054 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {'parent_id': 1}
>>> 2010-12-15 13:45:05,054 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> COMMIT
>>> 2010-12-15 13:45:05,055 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> BEGIN (implicit)
>>> 2010-12-15 13:45:05,056 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> SELECT parents.id AS parents_id
>>> FROM parents
>>> WHERE parents.id = %(param_1)s
>>> 2010-12-15 13:45:05,056 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {'param_1': 1}
>>> 2010-12-15 13:45:05,057 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> DELETE FROM parents WHERE parents.id = %(id)s
>>> 2010-12-15 13:45:05,057 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {'id': 1}
>>> 2010-12-15 13:45:05,058 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> ROLLBACK
>>> 2010-12-15 13:45:05,061 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> select relname from pg_class c join pg_namespace n on
>>> n.oid=c.relnamespace where n.nspname=current_schema() and
>>> lower(relname)=%(name)s
>>> 2010-12-15 13:45:05,061 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {'name': u'children'}
>>> 2010-12-15 13:45:05,063 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> select relname from pg_class c join pg_namespace n on
>>> n.oid=c.relnamespace where n.nspname=current_schema() and
>>> lower(relname)=%(name)s
>>> 2010-12-15 13:45:05,063 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {'name': u'parents'}
>>> 2010-12-15 13:45:05,064 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> DROP TABLE children
>>> 2010-12-15 13:45:05,064 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {}
>>> 2010-12-15 13:45:05,066 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> COMMIT
>>> 2010-12-15 13:45:05,067 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> DROP TABLE parents
>>> 2010-12-15 13:45:05,067 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> {}
>>> 2010-12-15 13:45:05,068 INFO sqlalchemy.engine.base.Engine.0x...f5d0
>>> COMMIT
>>> Traceback (most recent call last):
>>>  File "sharded_session_issue.py", line 64, in <module>
>>>    commit(session)
>>>  File "sharded_session_issue.py", line 47, in commit
>>>    session.commit()
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/session.py", line
>>> 623, in commit
>>>    self.transaction.commit()
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/session.py", line
>>> 385, in commit
>>>    self._prepare_impl()
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/session.py", line
>>> 369, in _prepare_impl
>>>    self.session.flush()
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/session.py", line
>>> 1397, in flush
>>>    self._flush(objects)
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/session.py", line
>>> 1478, in _flush
>>>    flush_context.execute()
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/unitofwork.py",
>>> line 304, in execute
>>>    rec.execute(self)
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/unitofwork.py",
>>> line 471, in execute
>>>    uow
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/mapper.py", line
>>> 2076, in _delete_obj
>>>    c = connection.execute(statement, del_objects)
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/engine/base.py", line
>>> 1191, in execute
>>>    params)
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/engine/base.py", line
>>> 1271, in _execute_clauseelement
>>>    return self.__execute_context(context)
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/engine/base.py", line
>>> 1302, in __execute_context
>>>    context.parameters[0], context=context)
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/engine/base.py", line
>>> 1401, in _cursor_execute
>>>    context)
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/engine/base.py", line
>>> 1394, in _cursor_execute
>>>    context)
>>>  File "/usr/lib/pymodules/python2.6/sqlalchemy/engine/default.py",
>>> line 299, in do_execute
>>>    cursor.execute(statement, parameters)
>>> sqlalchemy.exc.IntegrityError: (IntegrityError) update or delete on
>>> table "parents" violates foreign key constraint
>>> "children_parent_id_fkey" on table "children"
>>> DETAIL:  Key (id)=(1) is still referenced from table "children".
>>> 'DELETE FROM parents WHERE parents.id = %(id)s' {'id': 1}
>>> """
>>> 
>>> # Example Successful Run
>>> """
>>> 2010-12-15 13:45:40,471 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> BEGIN (implicit)
>>> 2010-12-15 13:45:40,472 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> INSERT INTO parents DEFAULT VALUES RETURNING parents.id
>>> 2010-12-15 13:45:40,472 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> {}
>>> 2010-12-15 13:45:40,473 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> INSERT INTO children (parent_id) VALUES (%(parent_id)s) RETURNING
>>> children.id
>>> 2010-12-15 13:45:40,473 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> {'parent_id': 1}
>>> 2010-12-15 13:45:40,474 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> INSERT INTO children (parent_id) VALUES (%(parent_id)s) RETURNING
>>> children.id
>>> 2010-12-15 13:45:40,474 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> {'parent_id': 1}
>>> 2010-12-15 13:45:40,475 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> COMMIT
>>> 2010-12-15 13:45:40,476 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> BEGIN (implicit)
>>> 2010-12-15 13:45:40,477 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> SELECT children.id AS children_id, children.parent_id AS
>>> children_parent_id
>>> FROM children
>>> WHERE children.id = %(param_1)s
>>> 2010-12-15 13:45:40,477 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> {'param_1': 1}
>>> 2010-12-15 13:45:40,478 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> SELECT children.id AS children_id, children.parent_id AS
>>> children_parent_id
>>> FROM children
>>> WHERE children.id = %(param_1)s
>>> 2010-12-15 13:45:40,478 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> {'param_1': 2}
>>> 2010-12-15 13:45:40,479 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> DELETE FROM children WHERE children.id = %(id)s
>>> 2010-12-15 13:45:40,479 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> ({'id': 1}, {'id': 2})
>>> 2010-12-15 13:45:40,480 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> SELECT parents.id AS parents_id
>>> FROM parents
>>> WHERE parents.id = %(param_1)s
>>> 2010-12-15 13:45:40,480 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> {'param_1': 1}
>>> 2010-12-15 13:45:40,481 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> DELETE FROM parents WHERE parents.id = %(id)s
>>> 2010-12-15 13:45:40,481 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> {'id': 1}
>>> 2010-12-15 13:45:40,482 INFO sqlalchemy.engine.base.Engine.0x...95d0
>>> COMMIT
>>> """
>>> 
>>> --
>>> You received this message because you are subscribed to the Google Groups 
>>> "sqlalchemy" group.
>>> To post to this group, send email to sqlalch...@googlegroups.com.
>>> To unsubscribe from this group, send email to 
>>> sqlalchemy+unsubscr...@googlegroups.com.
>>> For more options, visit this group at 
>>> http://groups.google.com/group/sqlalchemy?hl=en.
>>> 
>> 
>> --
>> You received this message because you are subscribed to the Google Groups 
>> "sqlalchemy" group.
>> To post to this group, send email to sqlalch...@googlegroups.com.
>> To unsubscribe from this group, send email to 
>> sqlalchemy+unsubscr...@googlegroups.com.
>> For more options, visit this group at 
>> http://groups.google.com/group/sqlalchemy?hl=en.
>> 
>> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to sqlalch...@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to