[sqlalchemy] Re: problem with backref
Michael Bayer ha scritto: Please, can you quote my original message? Google does not send me back the messages I post. dont access the unloaded b attribute on o unless it is still attached to its session. when you sess.close(), o is no longer attached to a session. Ok. I usually call sess.close and then sess.update to be sure that an object always belongs to the right session. (I use multiple threads, with Twisted). also, dont say del o.b, or insure that you reassign a blank list to o.b. before accessing it again. the del operation deletes the list-based attribute entirely and reverts access on it to its class-based lazy load status, which is why the lazy loader is firing off again. Thanks, now it works. Regards. Manlio Perillo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
Michael Bayer ha scritto: the original mapping essentially expressed this relationship: A -- cascade=all, delete-orphan -- B in both directions. What that means is, there cannot be an A with no B in the database, and there cannot be a B with no A in the database, i.e. its either A-B or both will be deleted. its like an oxygen molecule, or something. what you need to do is decide which of A and B can exist on its own without a parent relationship. since you want to delete rows from B and not A, that would indicate that the mapping should be: mapper(A, a) mapper( B, b, properties={ 'a': relation( A, backref=backref('b', lazy=False, uselist=False, cascade='all, delete-orphan'), uselist=False ) } ) i.e. the delete-orphan cascade is only in the direction from A-B. the cascade from B-A is left at its default value of save-update, so delete operations dont propigate from B's to A's. Sorry, I still have problems. Here is the code I'm using: from sqlalchemy import * db = create_engine('postgres://manlio:[EMAIL PROTECTED]/test', echo=True) metadata = BoundMetaData(db) a = Table( 'a', metadata, Column('x', String), Column('y', String), PrimaryKeyConstraint('x', 'y') ) b = Table( 'b', metadata, Column('x', String), Column('y', String), Column('z', String), PrimaryKeyConstraint('x', 'y'), ForeignKeyConstraint(['x', 'y'], ['a.x', 'a.y'], ondelete='CASCADE') ) metadata.create_all() class A(object): def __init__(self, x, y): self.x = x self.y = y class B(object): def __init__(self, x, y, z): self.x = x self.y = y self.z = z mapper(A, a) mapper( B, b, properties={ 'a': relation( A, backref=backref('b', lazy=False, uselist=False, cascade='all, delete-orphan'), uselist=False ) } ) try: 1 conn = db.connect() trans = conn.begin() sess = create_session(bind_to=conn) o = A('1', '2') o.b = B(o.x, o.y, '3') sess.save(o) sess.flush() sess.close() trans.commit() conn.close() 2 conn = db.connect() trans = conn.begin() sess = create_session(bind_to=conn) sess.update(o) print o.b.z del o.b #sess.delete(o.b) #o.b = None sess.flush() sess.close() trans.commit() conn.close() 3 print o.b s = a.select() print conn.execute(s).fetchall() finally: metadata.drop_all(tables=[b]) metadata.drop_all(tables=[a]) The error is: Traceback (most recent call last): File alchemy.py, line 82, in ? print o.b File /usr/lib/python2.4/site-packages/sqlalchemy/orm/attributes.py, line 48, in __get__ return self.get(obj) File /usr/lib/python2.4/site-packages/sqlalchemy/orm/attributes.py, line 205, in get value = callable_() File /usr/lib/python2.4/site-packages/sqlalchemy/orm/strategies.py, line 204, in lazyload raise exceptions.InvalidRequestError(Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed % (instance.__class__, self.key)) sqlalchemy.exceptions.InvalidRequestError: Parent instance class '__main__.A' is not bound to a Session, and no contextual session is established; lazy load operation of attribute 'b' cannot proceed Thanks and regards Manlio Perillo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
dont access the unloaded b attribute on o unless it is still attached to its session. when you sess.close(), o is no longer attached to a session. also, dont say del o.b, or insure that you reassign a blank list to o.b. before accessing it again. the del operation deletes the list-based attribute entirely and reverts access on it to its class-based lazy load status, which is why the lazy loader is firing off again. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
im sorry, i meant a scalar value of None, not a blank list,since you have uselist=False. Assign None to o.b instead of saying del o.b. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
Michael Bayer ha scritto: the original mapping essentially expressed this relationship: A -- cascade=all, delete-orphan -- B in both directions. What that means is, there cannot be an A with no B in the database, and there cannot be a B with no A in the database, i.e. its either A-B or both will be deleted. its like an oxygen molecule, or something. what you need to do is decide which of A and B can exist on its own without a parent relationship. since you want to delete rows from B and not A, that would indicate that the mapping should be: mapper(A, a) mapper( B, b, properties={ 'a': relation( A, backref=backref('b', lazy=False, uselist=False, cascade='all, delete-orphan'), uselist=False ) } ) i.e. the delete-orphan cascade is only in the direction from A-B. the cascade from B-A is left at its default value of save-update, so delete operations dont propigate from B's to A's. Thanks, this works. The problem was with my original exemple where I create a session without binding it to a connection. Regards Manlio Perillo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
Alan Franzoni ha scritto: The problem is that it requires the explicit use of the session. In my case this means that I can not delete the object inside a method of my class. class A(object): def enableB(enable=True): if enable: self.b = B(...) else: del self.b Not a big problem, however. There's the 'threadlocal' that should let you work as you like, but I've read its use is discouraged because it could lead to strange bugs. BTW, couldn't you just pass your session to the methods requiring it? class A(object): def enableB(enable=True, session): if enable: self.b = B(...) else: session.delete(self.b) A better solution is to do sess = object_session(self) Regards Manlio Perillo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
A better solution is to do sess = object_session(self) That's wonderful and I didn't know about it! Finally I'll give up passing session around my code! Thanks! -- Alan Franzoni [EMAIL PROTECTED] - Togli .xyz dalla mia email per contattarmi. Remove .xyz from my address in order to contact me. - GPG Key Fingerprint (Key ID = FE068F3E): 5C77 9DC3 BD5B 3A28 E7BC 921A 0255 42AA FE06 8F3E --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
Manlio Perillo ha scritto: Hi, I have a strange (for me) problem with backref. SQLAlchemy version is 0.3.1-1 on Debian Etch. Here is the code: [...] from sqlalchemy import * trans = conn.begin() sess = create_session() sess.update(o) print o.b.z del o.b A simple workaround is to remove cascade rules from the mapper and to do: sess.delete(o.b) However this require the explicit use of the session. Regards Manlio Perillo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
[italian mode] Come va Manlio? Ci sente anche qui alla fine :-) io per la fine dell'anno dovrei riuscire a finire il progetto su cui sto lavorando e potrĂ² riprendere finalmente il mio lavoro anche con python.it! [/italian mode] 1st: In order to use a transaction with a pre-existent connection, you should bind the session to the connection. This can be done by creating the session this way: sess = create_session(bind_to=conn) This is useful if you want to work both with the SQL layer and with the ORM layer of SA. If you just want to use the ORM layer (like you appear to do), forget the 'conn' and 'trans' in your code, and just do sess = create_session() trans = sess.create_transaction() and just use trans.rollback() or trans.commit() in your code. 2nd: If I got what you want: you want to be able to remove the 'B' instance from the 'A' instance without removing the 'A' object from the db, right? session.delete() is the way to go, because that's the way you remove objects using the SA ORM. And you must pull out the 'cascade='all'' from the 'a' relation, because if you instruct SA to do this, it will try to remove its related object (the 'A' instance), which is not what you wont. Look at this and tell me if it produces the result you would expect: mapper(A, a) mapper( B, b, properties={ 'a': relation( A, backref=backref('b', lazy=False, uselist=False, cascade='all'), uselist=False ) } ) sess = create_session() o = A('1', '2') o.b = B(o.x, o.y, '3') sess.save(o) sess.flush() sess.expunge(o) sess.clear() del o o = sess.query(A).get_by(x=1, y=2) print o.b.z sess.delete(o.b) sess.flush() sess.close() print o.b s = a.select() print s.execute().fetchall() -- Alan Franzoni [EMAIL PROTECTED] - Togli .xyz dalla mia email per contattarmi. Remove .xyz from my address in order to contact me. - GPG Key Fingerprint (Key ID = FE068F3E): 5C77 9DC3 BD5B 3A28 E7BC 921A 0255 42AA FE06 8F3E --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
Alan Franzoni ha scritto: [italian mode] Come va Manlio? Ci sente anche qui alla fine :-) io per la fine dell'anno dovrei riuscire a finire il progetto su cui sto lavorando e potrĂ² riprendere finalmente il mio lavoro anche con python.it http://python.it! [/italian mode] Hi Alan! 1st: In order to use a transaction with a pre-existent connection, you should bind the session to the connection. This can be done by creating the session this way: sess = create_session(bind_to=conn) This is useful if you want to work both with the SQL layer and with the ORM layer of SA. If you just want to use the ORM layer (like you appear to do), forget the 'conn' and 'trans' in your code, and just do sess = create_session() trans = sess.create_transaction() and just use trans.rollback() or trans.commit() in your code. In my code I use: trans = conn.begin() sess = create_session(bind_to=conn) The example posted was wrong, sorry. 2nd: If I got what you want: you want to be able to remove the 'B' instance from the 'A' instance without removing the 'A' object from the db, right? Right. session.delete() is the way to go, because that's the way you remove objects using the SA ORM. Yes, I just discovered this by myself. The problem is that it requires the explicit use of the session. In my case this means that I can not delete the object inside a method of my class. class A(object): def enableB(enable=True): if enable: self.b = B(...) else: del self.b Not a big problem, however. Thanks and regards Manlio Perillo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
The problem is that it requires the explicit use of the session. In my case this means that I can not delete the object inside a method of my class. class A(object): def enableB(enable=True): if enable: self.b = B(...) else: del self.b Not a big problem, however. There's the 'threadlocal' that should let you work as you like, but I've read its use is discouraged because it could lead to strange bugs. BTW, couldn't you just pass your session to the methods requiring it? class A(object): def enableB(enable=True, session): if enable: self.b = B(...) else: session.delete(self.b) -- Alan Franzoni [EMAIL PROTECTED] - Togli .xyz dalla mia email per contattarmi. Remove .xyz from my address in order to contact me. - GPG Key Fingerprint (Key ID = FE068F3E): 5C77 9DC3 BD5B 3A28 E7BC 921A 0255 42AA FE06 8F3E --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: problem with backref
the original mapping essentially expressed this relationship: A -- cascade=all, delete-orphan -- B in both directions. What that means is, there cannot be an A with no B in the database, and there cannot be a B with no A in the database, i.e. its either A-B or both will be deleted. its like an oxygen molecule, or something. what you need to do is decide which of A and B can exist on its own without a parent relationship. since you want to delete rows from B and not A, that would indicate that the mapping should be: mapper(A, a) mapper( B, b, properties={ 'a': relation( A, backref=backref('b', lazy=False, uselist=False, cascade='all, delete-orphan'), uselist=False ) } ) i.e. the delete-orphan cascade is only in the direction from A-B. the cascade from B-A is left at its default value of save-update, so delete operations dont propigate from B's to A's. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups sqlalchemy group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---