Reputation: 11159
I need to run the same exact query on multiple page requests. The first page renders the items, the second page exports the items to excel.
Storing the query directly on session fails because BaseQuery
is not JSON serializable:
session['previous_query'] = SomeModel.query
The next option is to store the query as a string:
session['previous_query'] = str(SomeModel.query)
This works but I would now need to run session.execute:
db.session.execute(session['previous_query'])
And that does not give me ORM objects but plain dicts without relationships.
Finally I can store only the ids, but that would require me to run the query on both ends multiple times and would not preserve the ordering I need.
Any suggestions?
Upvotes: 2
Views: 583
Reputation: 1121654
You can serialize the query with the SQLAlchemy Serializer extention:
from sqlalchemy.ext import serializer
session['previous_query'] = serializer.dumps(SomeModel.query, -1)
then reconstitute the query with:
query = serializer.loads(session['previous_query'], db.metadata, db.session)
objects = query.all()
where db
is your Flask-SQLAlchemy integration object.
Under the hood this uses the pickle
module but pickling has been customized to be more compact and to omit the session and engine references; these are loaded again when loading the serialized data with serializer.loads()
.
For this to work on Python 2 you do need to set the protocol version (second argument to serializer.dumps()
) as the seralization won't work with the default protocol version 0. Pick version 1 or 2 instead, or use -1
to pick the highest version supported by your Python installation.
Because this uses pickle, do be careful with loading the pickle from untrusted sources; a Flask session is tamper proof because it is cryptographically signed, but if an attacker ever was able to obtain your server-side secret then the attacker can take over your process by sending you a carefully crafted pickle for serializer.loads()
to load.
Upvotes: 4