简体   繁体   中英

Flask-SQLAlchemy : Manipulate attribute of a data upon fetching

I am using the following model to store data.

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    timestamp=db.Column(DateTime(timezone=True), nullable=False)


    def __init__(self, username, timestamp=None):
        self.username = username
        if timestamp is None:
            timestamp =datetime.datetime.now()
        self.timestamp = timestamp

    def __repr__(self):
        return '<User %r>' % self.username

Now, my question is : when fetching the data using

user = User.query.filter_by(username='admin').first()

I understand that the data will be fetched and converted into an User object?

All in all, what I want to accomplish is that when data is fetched, using the query as above, the data is manipulated automatically.

That is, here in my case, that the timestamp is made aware. I'll be using pytz.localize() to do this.

I tried :

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    timestamp=db.Column(DateTime(timezone=True), nullable=False)


    def __init__(self, username, timestamp=None):
        self.username = username
        if timestamp is None:
            timestamp =datetime.datetime.now()
        timestamp = pytz.utc.localize(timestamp)
        self.timestamp = timestamp

    def __repr__(self):
        return '<User %r>' % self.username

I thought of it as, when the object is initialized,

if(timestamp is none)
    new entry
    initialize timestamp
make timezone aware     #even if fetched from db
self.timestamp=timestamp`

But, it doesn't work. __init__ is not called when querying the data. What can be done?

I found in the sqlalchemy documentation that when recreating the object from a row it does not use __init__().

See: http://docs.sqlalchemy.org/en/latest/orm/constructors.html

The SQLAlchemy ORM does not call __init__ when recreating objects from database rows. The ORM's process is somewhat akin to the Python standard library's pickle module, invoking the low level __new__ method and then quietly restoring attributes directly on the instance rather than calling __init__.

If you need to do some setup on database-loaded instances before they're ready to use, you can use the @reconstructor decorator to tag a method as the ORM counterpart to __init__. SQLAlchemy will call this method with no arguments every time it loads or reconstructs one of your instances. This is useful for recreating transient properties that are normally assigned in your __init__:

from sqlalchemy import orm

class MyMappedClass(object):
    def __init__(self, data):
        self.data = data
        # we need stuff on all instances, but not in the database.
        self.stuff = []

    @orm.reconstructor
    def init_on_load(self):
        self.stuff = []

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM