views:

494

answers:

4

I want to do something like this:

f = Foo(bar='x')
session.add(f)
session.flush()

# do additional queries using f.id before commit()
print f.id # should be not None

session.commit()

But f.id is None when I try it. How can I get this to work?

-Dan

A: 

I'm no expert, but you might need to commit before you try to access the ID. Just flushing the session may not be enough.

f = Foo(bar='x')
session.add(f)
session.commit()
print f.id # should be not None
David Zaslavsky
I should have made it clear that I must use f.id before commit(). I know you can issue SQL during the INSERT (postgresql's RETURNING) to get the id back, and you can also issue a simple SELECT to get the same. All that is technically required is that the INSERT query be run against the db (isn't that what flush() does.) Maybe I will need to use hand-coded sql here.
Eloff
I thought you had to commit() to run an INSERT query. But as I said, I'm no expert. Why do you need to use the ID before commit() anyway?
David Zaslavsky
A: 

You should try using session.save_or_update(f) instead of session.add(f).

Mohit Ranka
`save_or_update` has been deprecated since 0.5 or so. `session.add()` should do it.
Pavel Repin
A: 

The answer is to not use sqlalchemy flush, or to even add the objects to the session. Doing the insert query manually in combination with postgres extension RETURNING id works well.

bind_params = []
for obj in new:
    d = obj.to_dict()
    d.pop('id', None)                
    bind_params.append(d)

r = session.execute(table.insert(postgres_returning=[table.c.id]), bind_params)
insert_ids = list(row[0] for row in r.fetchall())

for obj, id in izip(new, insert_ids):
    obj.__dict__['id'] = id
Eloff
+4  A: 

your sample code should be providing a value for f.id, assuming its an autogenerating primary key column. primary key attributes are populated immediately within the flush() process as they are generated and no call to commit() should be required. So the answer here lies in the details of your mapping, if there are any odd quirks of the backend in use (such as, SQLite doesn't generate integer values for a composite primary key) and/or what the emitted SQL says when you turn on echo.

zzzeek
You're correct, a quick check in the shell shows it populates the primary key field with a value. I'll have to investigate why it was not working in practice.
Eloff