[sqlalchemy] Re: problem with backref

2006-12-24 Thread Manlio Perillo


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

2006-12-23 Thread Manlio Perillo


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

2006-12-23 Thread Michael Bayer


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

2006-12-23 Thread Michael Bayer


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

2006-12-21 Thread Manlio Perillo


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

2006-12-21 Thread Manlio Perillo


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

2006-12-21 Thread Alan Franzoni



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

2006-12-20 Thread Manlio Perillo



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

2006-12-20 Thread Alan Franzoni

[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

2006-12-20 Thread Manlio Perillo


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

2006-12-20 Thread Alan Franzoni



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

2006-12-20 Thread Michael Bayer


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