TheOne
TheOne

Reputation: 11159

How to persist a query between flask page requests?

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

Answers (1)

Martijn Pieters
Martijn Pieters

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

Related Questions