Hi All,
I am using Flask-SQLAlchemy on a legacy database. My SQLA classes / tables
are setup using declarative base and autoload. In addition to using the
class to access persisted data, I also use plain old Python to enrich them
with ephemeral data.
Every time I load a User object, I'd like the instance for that particular
object / row to retain its plain old python instance data.
My understanding is that Flask-SQLAlchemy will by default use a separate
scoped_session for each request. And that means at the end of the request
session and user will go out of scope. So in the next request to
/users/Bob will instantiate a new User object whose will be reinitialized .
. . each time I make this request I will be told it was "asked 1 time".
Alternately, if I call /users_alt/Bob, then second time I call a
DetachedInstanceError will be raised when I attempt to read user.owners.
I suspect there's a pattern used to accomplish what I want to do, but I
have not tried the right Google search. Any recommendations on how to
approach this or searches to try / doc sections to read? The state I'm
storing in times_name_read_since_launch is actually complex enough that I
don't want to persist it and have to keep that dependent state synchronized.
Alternately is there a way for me to reattach a SQLA object to the current
requests' session? Then, ideally, I could get updates from the database to
User or Owner objects, but retain my ephemeral state in the plain old
python.
Thanks for the help,
Rob
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from sqlalchemy import orm
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = connection_string
db = SQLAlchemy(app)
class Owner(db.Model):
__table__ = db.Table('Owners', MetaData(), autoload=True, autoload_with=
db.engine)
class User(db.Model):
__table__ = db.Table('users', MetaData(), autoload=True, autoload_with=
db.engine)
owners = db.relationship('Owner', primaryjoin=
"foreign(User.userId)==remote(Owner.userId)", uselist=True,
backref=db.backref('user', uselist=False))
users_seen = dict()
@orm.reconstructor
def init_on_load(self):
self.times_name_read_since_launch = 0
@classmethod
def lookup_by_name(cls, name):
user_ = User.users_seen.get(name)
if user_ is None:
user_ = User.query.filter(User.UserName == name).one()
return user_
@classmethod
def store_by_name(cls, user_):
if user_.UserName not in User.users_seen:
User.users_seen[user_.UserName] = user_
@property
def name(self):
self.times_name_read_since_launch += 1
return self.UserName
@app.route("/users/<string:name>")
def user(name):
user_ = User.query.filter(User.UserName == name).one()
return "{} with {} - asked {} times".format(user_.name, user_.owners,
user_.times_name_read_since_launch)
@app.route("/users_alt/<string:name>")
def user_alt(name):
user_ = User.lookup_by_name(name)
User.store_by_name(user_)
owners = None
if user_.times_name_read_since_launch > 0:
# don't lazy load addresses the first request, simulates more
complex actual behavior desired
owners = user_.owners
return "{} with {} - asked {} times".format(user_.name, owners, user_.
times_name_read_since_launch)
db.create_all()
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
http://www.sqlalchemy.org/
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable
Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/sqlalchemy/66717a53-d81b-4cce-be68-601c5d673284%40googlegroups.com.