Record queries errors on some Postgres queries
stl-gilesbartonowen opened this issue · comments
Although the flask documentation claims it passes ExecutionContext objects optionally, it appears it sometimes passes PGExecutionContext_psycopg2
objects, which are not guaranteed to have a .statement
attribute. This means that line 111 in record_queries.py will throw the following:
File <FILE>, line 41, in <FN>
return context.fire_sequence(model_id_seq, None)
File "/usr/local/webapp/flask/lib/python3.8/site-packages/sqlalchemy/dialects/postgresql/base.py", line 2837, in fire_sequence
return self._execute_scalar(
File "/usr/local/webapp/flask/lib/python3.8/site-packages/sqlalchemy/engine/default.py", line 1658, in _execute_scalar
conn._cursor_execute(self.cursor, stmt, parameters, context=self)
File "/usr/local/webapp/flask/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 2189, in _cursor_execute
self.dispatch.after_cursor_execute(
File "/usr/local/webapp/flask/lib/python3.8/site-packages/sqlalchemy/event/attr.py", line 487, in __call__
fn(*args, **kw)
File "/usr/local/webapp/flask/lib/python3.8/site-packages/sqlalchemy/event/attr.py", line 174, in wrap_kw
return fn(**argdict)
File "/usr/local/webapp/flask/lib/python3.8/site-packages/flask_sqlalchemy/record_queries.py", line 111, in _record_end
statement=context.statement,
sqlalchemy.exc.StatementError: (builtins.AttributeError) 'PGExecutionContext_psycopg2' object has no attribute 'statement'
I appreciate this is somewhat an issue with Flask but I think this can be handled in a safe way within flask-alchemy, especially given when these contexts are passed in they don't actually have the fired sequence sql in, but rather the broader insert. The listener functions are called with "statement" as a kwarg so I think there's a strong argument to use that primarily.
This is the case I've found so far:
from sqlalchemy.sql import Sequence
db = SQLAlchemy()
field_sequence = Sequence("field_sequence")
def get_default_field(context):
if context.get_current_parameters()['set_field']:
return context.fire_sequence(field_sequence, None)
class MyModel(db.Model):
set_field = db.Column(db.Boolean)
field = db.Column(db.BigInteger, default=get_default_field, nullable=True)
m = MyModel(set_field=True)
db.session.add(m)
db.session.flush()
Environment:
- Python version: 3.8.16
- Flask-SQLAlchemy version: 3.1.1
- Flask version: 2.3.3
- SQLAlchemy version: 2.0.21