[Sorry if this makes it onto the list twice. I posted through Gmane NNTP and was told the message was sent to moderation. I haven't seen it appear on the list yet.]
Greetings. I've got a database with a parent/children relationship (one-to-many, to clarify). When a parent is deleted, all children should be deleted; this is reflected in the schema (ON DELETE CASCADE) as well as in the SA relationship (private=True). However, I'm running into problems in the case where a child's parent needs to be changed. I've demonstrated this in the test script included below. As near as I can tell the reassignment works like: (1) Delete child from old parent. (a) Parent says "my children are private, so delete the child." (2) Add child to new parent, resulting in an exception because the child has been deleted. It looks to me like this trouble may originate around GenericBackrefExtension.set(), where it does a "remove" followed by an "append." I tried to step through this code but I wasn't able to follow it. Would it be possible to modify this code (or modify elsewhere) so that the calls to remove the object from the parent know that the child is not being removed, but reassigned to a different parent? I.e., ignore the private=True for cases of reassigning a parent? Or, alternatively, will anyone kindly suggest a recipe for getting around this problem? The only way I've found is something roughly like (using variables from below test): child.foo_id = new_parent.id child.commit() # Actually issues SQL UPDATE statement objectstore.refresh(child) # If you don't refresh, child.foo is None assert child.new is new_parent Thanks for any assistance, and thanks for SA. Dale ---- from sqlalchemy import * # -- PostgreSQL 8.1.3, using the following schema: # # CREATE TABLE foo (id INTEGER PRIMARY KEY); # CREATE TABLE bar (id INTEGER PRIMARY KEY, # foo_id INTEGER REFERENCES foo (id) NOT NULL # ON DELETE CASCADE); # INSERT INTO foo VALUES (1); # INSERT INTO foo VALUES (2); # INSERT INTO bar VALUES (3, 1); db_uri = "postgres://database=oit_pwdb&user=oit_pwdb&password=qipiY24P" engine = create_engine(db_uri, echo=True) foos = Table("foo", engine, autoload=True) bars = Table("bar", engine, autoload=True) class Foo (object): pass assign_mapper(Foo, foos) class Bar (object): pass assign_mapper(Bar, bars) cascade_mappers(Foo, Bar) Foo.mapper.add_property("bars", relation(Bar, backref="foo", private=True)) # Actual problem section is here. child = Bar.get(3) old_parent = Foo.get(1) assert child.foo is old_parent, "test setup failed" new_parent = Foo.get(2) child.foo = new_parent # The above statement raises the following exception: # # File # ".../python2.4/site-packages/SQLAlchemy-0.1.5-py2.4.egg/sqlalchemy/mapping/unitofwork.py", # line 47, in list_value_changed # raise InvalidRequestError("re-inserting a deleted value into a list") # Never get here. child.commit() assert child.foo_id == new_parent.id, "parent change failed" ------------------------------------------------------- This SF.Net email is sponsored by xPML, a groundbreaking scripting language that extends applications into web and mobile media. Attend the live webcast and join the prime developer group breaking into this new coding territory! http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642 _______________________________________________ Sqlalchemy-users mailing list Sqlalchemy-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users