For now I have an unoptimized solution working.   I don't ever keep a 
reference to the SQLA instance and in the reconstructor I reattach the 
ephemeral state.  Something like.

class User(db.Model):
  __data_cache = dict()

  @orm.reconstructor
  def init_on_load(self):
    data = User.__data_cache.get(self.id)
    if data is None:
      User.__data_cache[self.id] = 0
    User.__data_cache[self.id] += 1

Rob


On Wednesday, February 12, 2020 at 9:43:37 PM UTC-6, Rob Rosenfeld wrote:
>
> Thanks for the thoughts.  I'm going to digest, read docs, and experiment. 
>
>
> On Wed, Feb 12, 2020 at 8:52 AM Mike Bayer <mik...@zzzcomputing.com 
> <javascript:>> wrote:
>
>>
>>
>> On Tue, Feb 11, 2020, at 11:41 PM, Rob Rosenfeld wrote:
>>
>> 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.  
>>
>>
>> you can get a plain reattach without it emitting any SQL using 
>> session.add():
>>
>>
>> session.add(detached_object)
>>
>>
>> however, if you're not sure if detached_object's primary key might have 
>> been loaded already, you would want to use session.merge() instead.  if 
>> your object has no changes on it you can add load=False which will avoid a 
>> SQL round trip.
>>
>>
>>
>>
>> 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 sqlal...@googlegroups.com <javascript:>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/sqlalchemy/66717a53-d81b-4cce-be68-601c5d673284%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/sqlalchemy/66717a53-d81b-4cce-be68-601c5d673284%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>>
>> -- 
>> 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 a topic in the 
>> Google Groups "sqlalchemy" group.
>> To unsubscribe from this topic, visit 
>> https://groups.google.com/d/topic/sqlalchemy/NS4PbZ2nLwU/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to 
>> sqlal...@googlegroups.com <javascript:>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/sqlalchemy/31e0db24-1a1a-4099-8510-d9568fb97ca0%40www.fastmail.com
>>  
>> <https://groups.google.com/d/msgid/sqlalchemy/31e0db24-1a1a-4099-8510-d9568fb97ca0%40www.fastmail.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/66f49a41-1b79-46d5-8719-5badb758983a%40googlegroups.com.

Reply via email to