I'm a newbie to Flask and SQLAlchemy (been working with Django for the last 3 years). I need to call an existing PostgreSQL function that writes to 3 different tables in a database. This is out of my control (I just have to make it work). The function returns a record (custom Postgres type) with information about the results. Here is the code:
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
...
retval = db.engine.execute(
'SELECT * FROM add_purchase(%s, %s, %s, %s, %s, %s, %s);',
clean_data.account_id, amount, tax, deposit, clean_data.pos_id,
g.token_id, clean_data.external_reference_id).first()
app.logger.info(retval) # for debugging
db.session.commit()
The above code runs without error. From the log message, I can see the the correct data is getting returned from the database. However, if I go to psql, I cannot see the newly inserted data. It would seem that the transaction is never actually committed.
Most of the documentation and examples I can find are based on using SQLAlchemy's ORM. What am I doing wrong here?
Stack info:
Flask==0.10.1
Flask-SQLAlchemy==1.0
psycopg2==2.5.2
Python 2.7.3
Postgresql 9.3
Update
I have figured out a way to make it work, here is a sample that actually works for me:
from sqlalchemy import exc
...
connection = db.engine.connect()
trans = connection.begin()
try:
retval = connection.execute(
'SELECT * FROM add_purchase(%s, %s, %s, %s, %s, %s, %s);',
clean_data.account_id, amount, tax, deposit,
clean_data.pos_id, g.token_id,
clean_data.external_reference_id).first()
except exc.SQLAlchemyError:
trans.rollback()
raise
else:
trans.commit()
And I've reviewed the code in SQLAlchemy's connect method. It seems like calling "connect()" just gets a new connection from the pool (which seem to be set to size=5 by default - at least I'm not setting it to 5). So, I'm not sure if there is much harm in it. However, it seems like there should be away to make this code cleaner by making the example in the original question work. I'm still hoping someone can tell me how to do that.
If you want to commit all changes to the PostgreSQL database permanently, you call the commit() method. And in case you want to cancel the changes, you call the rollback() method. Closing the connection object or destroying it using the del will also result in an implicit rollback.
The only solution to commit within "DO" blocks (or functions) (for Postgresql version less then 11) is to use dblink connection to the same server an execute your queries there. Just keep in mind variables and temporary objects visibility.
If you are using raw SQL with SQLAlchemy, then I think you have to issue the BEGIN and COMMIT statements yourself. Try adding something like this:
...
begin_retval = db.engine.execute('BEGIN;')
retval = db.engine.execute('SELECT * FROM add_purchase(%s, %s, %s, %s, %s, %s, %s);',
clean_data.account_id, amount, tax, deposit, clean_data.pos_id,
g.token_id, clean_data.external_reference_id).first()
commit_retval = db.engine.execute('COMMIT;')
...
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