22

I want to specify the return values for a specific update in sqlalchemy.

The documentation of the underlying update statement (sqlalchemy.sql.expression.update) says it accepts a "returning" argument and the docs for the query object state that query.update() accepts a dictionary "update_args" which will be passed as the arguments to the query statement.

Therefore my code looks like this:

session.query(
  ItemClass
).update(
  {ItemClass.value: value_a},
  synchronize_session='fetch',
  update_args={
    'returning': (ItemClass.id,)
  }
)

However, this does not seem to work. It just returns the regular integer.

My question is now: Am I doing something wrong or is this simply not possible with a query object and I need to manually construct statements or write raw sql?

1
  • 5
    It's not possible. Query.update is clearly documented to return "the count of rows matched as returned by the database’s “row count” feature", not the result of the update query. Commented Aug 23, 2017 at 18:00

2 Answers 2

9

The full solution that worked for me was to use the SQLAlchemy table object directly.

You can get that table object and the columns from your model easily by doing

table = Model.__table__
columns = table.columns

Then with this table object, I can replicate what you did in the question:

from your_settings import db

update_statement = table.update().returning(table.id)\
    .where(columns.column_name=value_one)\
    .values(column_name='New column name')
result = db.session.execute(update_statement)

tuple_of_results = result.fetchall()

db.session.commit()

The tuple_of_results variable would contain a tuple of the results. Note that you would have to run db.session.commit() in order to persist the changes to the database as you it is currently running within a transaction.

You could perform an update based on the current value of a column by doing something like:

update_statement = table.update().returning(table.id)\
    .where(columns.column_name=value_one)\
    .values(like_count=table_columns.like_count+1)

This would increment our numeric like_count column by one.

Hope this was helpful.

Sign up to request clarification or add additional context in comments.

3 Comments

Hi! I'd like to ensure that other threads can't go between the update and the commit. Does this solution accomplish that?
You would have to make the transaction(or db session) SERIALIZABLE. See this link for more details
You can get more information about DB isolation levels from this video
6

Here's a snippet from the SQLAlchemy documentation:

# UPDATE..RETURNING
result = table.update().returning(table.c.col1, table.c.col2).\
    where(table.c.name=='foo').values(name='bar')
print result.fetchall()

4 Comments

Don't believe that works for the way they're using query.update() ...
what does table mean here? what is table.c?
@mymedia table is the sqlalchemy Table object. table.c is the collection of columns in that table. Check out docs.sqlalchemy.org/en/13/core/selectable.html
@courtsimas the APIs are a bit different if you work with selectables or with session and query objects, but all support returning if the backend supports returning I think.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.