Both mv and ml will not be recognized, since you haven't defined them as variables.
The second argument of execute statement is a dictionary, and all the elements of your plain query "UPDATE client SET musicVol = :mv , messageVol = :ml" escaped with a colon are being searched for in this dictionary's keys. The execute method did not found a key 'mv' nor 'ml' in this dictionary, therefore an error is raised.
This is the correct version:
db.my_session.execute(
"UPDATE client SET musicVol = :mv, messageVol = :ml",
{'mv': music_volume, 'ml': message_volume}
)
Answer from mpiskore on Stack OverflowFlask sql alchemy - how do I get raw SQL (with real parameters?)
Videos
I hope that it is OK to post this question here, although it is not strictly related to Flask. I couldn't find a better place to post it.
Context: Flask, SQLAlchemy and MySQL
I am looking for a way to convert a query object to raw SQL and parameters and save this in a dictionary, in order to be able to pickle dump and load the dictionary before executing the query. How can I achieve converting the query and then executing the text and parameters with SQLAlcehmy?
I'd be eternally grateful if anyone could point me in the right direction.
The documentation uses literal_binds to print a query q including parameters:
print(q.statement.compile(compile_kwargs={"literal_binds": True}))
the above approach has the caveats that it is only supported for basic types, such as ints and strings, and furthermore if a bindparam() without a pre-set value is used directly, it won’t be able to stringify that either.
The documentation also issues this warning:
Never use this technique with string content received from untrusted input, such as from web forms or other user-input applications. SQLAlchemy’s facilities to coerce Python values into direct SQL string values are not secure against untrusted input and do not validate the type of data being passed. Always use bound parameters when programmatically invoking non-DDL SQL statements against a relational database.
This blogpost by Nicolas Cadou provides an updated answer.
Quoting from the blog post, this is suggested and worked for me:
from sqlalchemy.dialects import postgresql print str(q.statement.compile(dialect=postgresql.dialect()))
Where q is defined as:
q = DBSession.query(model.Name).distinct(model.Name.value) \ .order_by(model.Name.value)
Or just any kind of session.query().
The question is a bit old already, but knowing myself, I will probably come back for this in future. This was the bit of code I was looking for:
import sqlalchemy
from sqlalchemy.sql.expression import bindparam
from sqlalchemy.types import String
from sqlalchemy.dialects.postgresql import ARRAY
DB_URI = '...'
engine = sqlalchemy.create_engine(DB_URI)
sql = text("SELECT * FROM some_table WHERE userid = :userid").bindparams(bindparam("userid", String))
res = engine.execute(sql, userid=12345)
# in particular this bit is useful when you have a list of ids
sql = text("SELECT * FROM some_table WHERE userids = :userids").bindparams(bindparam("userids", ARRAY(String)))
res = engine.execute(sql, userids=[12345, 12346, 12347])
From what I see, there are two kind of "duh" ways to do it if I am not missing anything -
1st Way WARNING THIS IS SUSCEPTIBLE TO SQL INJECTION ATTACKS, DO NOT USE IN PRODUCTION
userid=12345 # defining here
sql = text("SELECT * FROM some_table WHERE userid = '"+userid+"'")
res = engine.execute(sql)
2nd Way
sql = text("SELECT * FROM some_table WHERE userid = :userid")
res = engine.execute(sql, userid=str(12345))