I'm using SQLAlchemy with python and i want to update specific row in a table which equal this query:
UPDATE User SET name = 'user' WHERE id = '3'
I made this code by sql alchemy but it's not working:
session.query(User).filter(User.id==3).update({'name': 'user'})
returned this error:
InvalidRequestError: Could not evaluate current criteria in Python. Specify 'fetch' or False for the synchronize_session parameter.
How can i do it?
ormically, you don't use update(), you set attributes:
a_user = session.query(User).filter(User.id == 3).one()
a_user.name = "user"
session.commit()
session.query(User).filter(User.id==3).update({'name':'user'},synchronize_session=False)
This would work. Read about syncrhonize_session in sqlalchemy documentation.
Related
Original question
I have set up a soft deletion on SQLAlchemy 1.4 based on this example in the official doc here. The
_add_filtering_criteria filters out the soft-deleted objects whenever the execute_state.execution_options "include_deleted" is False.
At some point, I would like that some queries are able to search in the soft-deleted objects. I am able to do it per queries, i.e. specifying query.execution_options(include_deleted=True) but I would like to make all queries of a particular session include soft-deleted objects without having to specify it for each query.
I have tried to declare the execution_options(include_deleted=True) on the engine's creation but it does not work.
from sqlalchemy import orm
class SoftDeleted:
deletion_date = Column(DateTime, nullable=True)
#event.listens_for(orm.Session, "do_orm_execute")
def _add_filtering_criteria(execute_state: orm.ORMExecuteState) -> None:
"""Intercepts all ORM queries. Adds a with_loader_criteria option to all
of them.
This option applies to SELECT queries and adds a global WHERE criteria
(or as appropriate ON CLAUSE criteria for join targets)
to all objects of a certain class or superclass.
"""
if (not execute_state.is_column_load
and not execute_state.is_relationship_load
and not execute_state.execution_options.get("include_deleted", False)):
execute_state.statement = execute_state.statement.options(
orm.with_loader_criteria(
SoftDeleted,
lambda cls: cls.deletion_date.is_(None),
include_aliases=True,
)
)
engine = sa.create_engine(url, echo=False).execution_options(include_deleted=True)
session_factory = orm.sessionmaker(bind=engine)
session = session_factory()
# let SomeClass be a class that inherits from the SoftDeleted mixin
myquery = session.query(SomeClass).get(1)
# will not retrieve SomeClass with uid=1 if it is soft-deleted
myquery2 = session.query(SomeClass).execution_options(include_deleted=True).get(1)
# will retrieve SomeClass with uid=1 even if it is soft-deleted
As I said, I would like that all queries of the session are able to include soft-deleted objects. Would someone know how I can do?
Solution, thanks to snakecharmerb's answer
After snakecharmerb answers, I modified the following and I got the wanted behaviour
#event.listens_for(orm.Session, "do_orm_execute")
def _add_filtering_criteria(execute_state):
if (not execute_state.is_column_load
and not execute_state.is_relationship_load
and not execute_state.execution_options.get("include_deleted", False)
and not execute_state.session.info.get("include_deleted", False)):
[...]
engine = sa.create_engine(url, echo=False) \
.execution_options(include_deleted=include_deleted)
session_factory = orm.sessionmaker(
bind=engine,
info={'include_deleted':
engine.get_execution_options().get('include_deleted', False)})
session = session_factory()
[...]
You have set your flag in the engine's execution options, so you must retrieve it from there. The engine can be accessed through the session's bind attribute:
(Pdb) execute_state.session.bind.get_execution_options()
immutabledict({'include_deleted': True})
Your code does not error because execute_state has an execution_options attribute, but it contains other things:
(Pdb) execute_state.execution_options
immutabledict({'_sa_orm_load_options': <class 'sqlalchemy.orm.context.QueryContext.default_load_options'>, '_result_disable_adapt_to_context': True, 'future_result': True})
Session objects (and sessionsmakers) have an info attribute, a dictionary that you can populate as you wish. This could used to pass the flag if you wanted to set the flag per session rather than per engine.
I got table like this:
class ReportImages(Base):
__tablename__ = 'very_long_name_of_table'
id = Column('long_column_name', Integer, primary_key=True)
And i run select from Oracle Database it raises exception:
sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) ORA-00972: identifier is too long
[SQL: SELECT very_long_name_of_table.long_column_name AS very_long_name_of_table_long_column_name FROM very_long_name_of_table]
How can is set my own alias for select or not to use column aliases at all?
Select like
data = session.query(ReportImages).all()
Solved it with setting alias before query:
ri = aliased(ReportImages, name='ri')
data = session.query(ri)
It works, but still interesting how i can set label styling in ReportImages class.
I am trying to access pre-created MySQL View in the database via. peewee treating it as a table [peewee.model], however I am still prompted with Operational Error 1054 unknown column.
Does PeeWee Supports interactions with database view ?
Peewee has been able to query against views when I've tried it, but while typing up a simple proof-of-concept I ran into two potential gotcha's.
First, the code:
from peewee import *
db = SqliteDatabase(':memory:')
class Foo(Model):
name = TextField()
class Meta: database = db
db.create_tables([Foo])
for name in ('huey', 'mickey', 'zaizee'):
Foo.create(name=name)
OK -- nothing exciting, just loaded three names into a table. Then I made a view that corresponds to the upper-case conversion of the name:
db.execute_sql('CREATE VIEW foo_view AS SELECT UPPER(name) FROM foo')
I then tried the following, which failed:
class FooView(Foo):
class Meta:
db_table = 'foo_view'
print [fv.name for fv in FooView.select()]
Then I ran into the first issue.
When I subclassed "Foo", I brought along a primary key column named "id". Since I used a bare select() (FooView.select()), peewee assumed i wasnted both the "id" and the "name". Since the view has no "id", I got an error.
I tried again, specifying only the name:
print [fv.name for fv in FooView.select(FooView.name)]
This also failed.
The reason this second query fails can be found by looking at the cursor description on a bare select:
curs = db.execute_sql('select * from foo_view')
print curs.description[0][0] # Print the first column's name.
# prints UPPER(name)
SQLite named the view's column "UPPER(name)". To fix this, I redefined the view:
db.execute_sql('CREATE VIEW foo_view AS SELECT UPPER(name) AS name FROM foo')
Now, when I query the view it works just fine:
print [x.name for x in FooView.select(FooView.name)]
# prints ['HUEY', 'MICKEY', 'ZAIZEE']
Hope that helps.
I am trying to get this setup to work, the database is created correctly, but trying to insert data I get the following error:
On sqlite:
sqlalchemy.exc.OperationalError
OperationalError: (sqlite3.OperationalError) no such column: Author [SQL: u'SELECT count(*) AS count_1 \nFROM (SELECT Author) AS anon_1']
On postgres:
sqlalchemy.exc.ProgrammingError
ProgrammingError: (psycopg2.ProgrammingError) column "author" does not exist
LINE 2: FROM (SELECT Author) AS anon_1
^
[SQL: 'SELECT count(*) AS count_1 \nFROM (SELECT Author) AS anon_1']
edit: Perhaps this has to do with it: I don't understand why it says "anon_1", as I am using credentials clearly?
I have inspected postgres and sqlite and the tables are created correctly. It seems to be an ORM configuration error, as it only seems to happend on inspecting or creating entries, any suggestion would be welcome!
class Author(CommonColumns):
__tablename__ = 'author'
author = Column(String(200))
author_url = Column(String(2000))
author_icon = Column(String(2000))
comment = Column(String(5000))
registerSchema('author')(Author)
SETTINGS = {
'SQLALCHEMY_TRACK_MODIFICATIONS': True,
'SQLALCHEMY_DATABASE_URI': 'sqlite:////tmp/test.db',
# 'SQLALCHEMY_DATABASE_URI': 'postgresql://xxx:xxx#localhost/test',
}
application = Flask(__name__)
# bind SQLAlchemy
db = application.data.driver
Base.metadata.bind = db.engine
db.Model = Base
db.create_all()
if __name__ == "__main__":
application.run(debug=True)
What is the query you're using to insert data?
I think the error messages may be a bit more opaque than they need to be because you're using Author/author in three very similar contexts:
the Class name
the table name
the column name
For easier debugging, the first thing I'd do is temporarily make each one unique (AuthorClass, author_table, author_column) so you can check which 'Author' is actually being referred to by the error message.
Since you're using the ORM, I suspect the underlying issue is that your insert statement uses Author (the object) when it should actually be using Author.author (the attribute/column name). The SELECT statements are complaining that they can't find the column 'author', but because you use author for both the table and column name, it's unclear what's actually being passed into the SQL statement.
I have this table in my database (using Posgresql and Sqlalchemy) called "participants".
In my models.py I want to access the participant's records. Since participants is not in my models.py and resides as a table in my db, when I do query = db.session.query('participants').order_by('name').all() I get an error:
ProgrammingError: (ProgrammingError) column "participants" does not exist
LINE 1: SELECT participants ORDER BY name
^
What can I do to retrieve this information?
Like the comment on the original post, did something like:
query = db.engine.execute('select * from participants order by name')
This doesn't give it in the same format as the query so I could use it for what I needed (a dictionary output, and a format for web), so I did:
partner_list = []
for record in query:
record_dict = dict(record)
partner_list.append(record_dict)