I have an sqlalchemy core bulk update query that I need to programmatically pass the name of the column that is to be updated.
The function looks as below with comments on each variable:
def update_columns(table_name, pids, column_to_update):
'''
1. table_name: a string denoting the name of the table to be updated
2. pid: a list of primary ids
3. column_to_update: a string representing the name of the column that will be flagged. Sometimes the name can be is_processed or is_active and several more other columns. I thus need to pass the name as a parameter.
'''
for pid in pids:
COL_DICT_UPDATE = {}
COL_DICT_UPDATE['b_id'] = pid
COL_DICT_UPDATE['b_column_to_update'] = True
COL_LIST_UPDATE.append(COL_DICT_UPDATE)
tbl = Table(table_name, meta, autoload=True, autoload_with=Engine)
trans = CONN.begin()
stmt = tbl.update().where(tbl.c.id == bindparam('b_id')).values(tbl.c.column_to_update==bindparam('b_column_to_update'))
trans.commit()
The table
parameter gets accepted and works fine.
The column_to_update
doesn't work when passed as a parameter. It fails with the error raise AttributeError(key) AttributeError: column_to_mark
. If I however hard code the column name, the query runs.
How can I pass the name of the column_to_update
for SQLAlchemy to recognize it?
EDIT: Final Script
Thanks to @Paulo, the final script looks like this:
def update_columns(table_name, pids, column_to_update):
for pid in pids:
COL_DICT_UPDATE = {}
COL_DICT_UPDATE['b_id'] = pid
COL_DICT_UPDATE['b_column_to_update'] = True
COL_LIST_UPDATE.append(COL_DICT_UPDATE)
tbl = Table(table_name, meta, autoload=True, autoload_with=Engine)
trans = CONN.begin()
stmt = tbl.update().where(
tbl.c.id == bindparam('b_id')
).values(**{column_to_update: bindparam('b_column_to_update')})
CONN.execute(stmt, COL_LIST_UPDATE)
trans.commit()
To access the column names we can use the method keys() on the result. It returns a list of column names. Since, we queried only three columns, we can view the same columns on the output as well.
SQLAlchemy Core The already created students table is referred which contains 4 columns, namely, first_name, last_name, course, score. But we will be only selecting a specific column. In the example, we have referred to the first_name and last_name columns. Other columns can also be provided in the entities list.
A client-side SQL expression, a server_default value, and server-side implicit defaults and triggers all have the server generate the default, which then must be fetched by the client if you want to be able to access it in the same SQLAlchemy session.
The statement ends by calling subquery() , which tells SQLAlchemy that our intention for this query is to use it inside a bigger query instead of on its own.
I'm not sure if I understood what you want, and your code looks very different from what I consider idiomatic sqlalchemy (I'm not criticizing, just commenting we probably use orthogonal code styles).
If you want to pass a literal column as a parameter use:
from sqlalchemy.sql import literal_column
...
tbl.update().where(
tbl.c.id == bindparam('b_id')
).values({
tbl.c.column_to_update: literal_column('b_column_to_update')
})
If you want to set the right side of the expression dynamically, use:
tbl.update().where(
tbl.c.id == bindparam('b_id')
).values({
getattr(tbl.c, 'column_to_update'): bindparam('b_column_to_update')
})
If none of this is not what you want, comment on the answer or improve your question and I will try to help.
[update]
The values
method uses named arguments like .values(column_to_update=value)
where column_to_update
is the actual column name, not a variable holding the column name. Example:
stmt = users.update().\
where(users.c.id==5).\
values(id=-5)
Note that where
uses the comparison operator ==
while values
uses the attribution operator =
instead - the former uses the column object in a Boolean expression and the latter uses the column name as a keyword argument binding.
If you need it to be dynamic, use the **kwargs
notation: .values(**{'column_to_update': value})
But probably you want to use the values
argument instead of the values
method.
There is also another simple way:
tbl.c[column_name_here]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With