I have two models, one is User and the other Address user can have many
email addresses.
# create and save to database
user = User("bob")
address1 = Address("bo...@bob.com")
address2 = Address("bo...@bob.com")
user.addresses.append(address1)
user.addresses.append(address2)
session.commit()
# Now I delete one of the addresses after querying for it
address2.delete()
# if I print the number of addresses, I get what's in the database, not
the session
print str(len(user.addresses)) # This outputs 2 not 1
session.commit()
# after a commit, the result now includes the deletion
print str(len(user.addresses)) # This outputs 1
I would like to output the number of addresses (to update an edit
dialog) without commiting, since the user can still cancel and rollback
the change.
After all that, I had a brain-wave. Using the session to do the query:
session.query(Address).filter(Address.user_id == user.id).count()
Now this works. But is this the right way to do it? Am I setting myself
up for a massive failure at some point? Or, is there just a better way
to do it?
Thanks,
Jon
> How can I see updates to entities that have not yet been committed to
> the database?
At first, I thought you were looking for session.new, session.dirty &
session.deleted
> For example:
>
> I have two models, one is User and the other Address user can have many
> email addresses.
>
> # create and save to database
>
> user = User("bob")
> address1 = Address("bo...@bob.com")
> address2 = Address("bo...@bob.com")
> user.addresses.append(address1)
> user.addresses.append(address2)
> session.commit()
>
> # Now I delete one of the addresses after querying for it
>
> address2.delete()
>
> # if I print the number of addresses, I get what's in the database, not
> the session
>
> print str(len(user.addresses)) # This outputs 2 not 1
>
> session.commit()
>
> # after a commit, the result now includes the deletion
>
> print str(len(user.addresses)) # This outputs 1
>
> I would like to output the number of addresses (to update an edit
> dialog) without commiting, since the user can still cancel and rollback
> the change.
This is a FAQ in SQLAlchemy:
See http://www.sqlalchemy.org/trac/wiki/FAQ#Imcallingdeletemyobjectanditisntremovedfromtheparentcollection
So in your case that means:
session.expire(user, ['addresses'])
There are other options though, see the linked page.
--
Gaëtan de Menten
http://openhex.org
> This is a FAQ in SQLAlchemy:
> See http://www.sqlalchemy.org/trac/wiki/FAQ#Imcallingdeletemyobjectanditisntremovedfromtheparentcollection
>
> So in your case that means:
>
> session.expire(user, ['addresses'])
>
> There are other options though, see the linked page.
>
Is that really it? The article mentions using cascading, which I am already using. Doesn't that just mean that when I mark something to be deleted, it very nicely marks dependencies to be deleted? session.expire sounds like it will mark an entity as changed so that when I access it, it will re-read the result from the database. My problem is that I've not committed anything, so it will read the state prior to my changes.
What that article implies is that you can have the instance both
deleted and removed from the list ("addresses" in this case), by using
cascades AND change your code to remove the instance from the list
instead of deleting it directly, as the cascade will "delete the
instance" automatically. So instead of doing
address2.delete()
you would do:
user.addresses.remove(address2)
> session.expire sounds like it will mark an entity as changed so that when I access it, it will re-read the result from the database. My problem is that I've not committed anything, so it will read the state prior to my changes.
Nope, it won't. The thing is that, if you use the default session, it
is "autoflush", which means, it'll flush what you have in the session
*before* doing any query.
That works great. I didn't realise that working on the collection would
also update the session. That's good to know. Thanks.
My problem now is probably unrelated to this, but I'll ask anyhow.
If the user selects to delete an email address, I call
user.addresses.remove(address1). Instead of pressing ok to confirm
(where I'd call session.commit()), they cancel it. How can I undo that
deletion? I can't do session.rollback because at this point, other
changes may have been made to the user (for example, they edited their
name), and it should still be possible to commit these changes.
I think that I need transactions for this, but perhaps I'm wrong.