python - How to update parent table timestamp when child table is modified? -
how can update parent timestamp when child table modified?
i use parent table timestamp checking if rest client should update it's local version of these tables.
class parent(db.model): id = db.column(db.integer, primary_key=true) version = db.column(db.integer) timestamp = db.column(db.datetime, default=datetime.utcnow, onupdate=datetime.utcnow) childs = db.relationship('children', backref='parent', lazy='dynamic', cascade="all, delete-orphan") class children(db.model): id = db.column(db.integer, primary_key=true) version = db.column(db.integer) timestamp = db.column(db.datetime, default=datetime.utcnow, onupdate=datetime.utcnow) parent_id = db.column(db.integer, db.foreignkey('parent.id'), nullable=false)
and test this:
db.create_all() parent = parent(version=1) child = children(version=1, parent=parent) db.session.add_all([parent, child]) db.session.commit() print "parent timestamp: %s, child timestamp %s" % (parent.timestamp, child.timestamp) previous_timestamp = parent.timestamp parent.version = 2 db.session.add(parent) db.session.commit() assert parent.timestamp != previous_timestamp # works print "parent timestamp: %s, child timestamp %s" % (parent.timestamp, child.timestamp) previous_timestamp = parent.timestamp child.version = 2 db.session.add(child) db.session.commit() # fails. parent timestamp not updated when child modified assert parent.timestamp != previous_timestamp print "parent timestamp: %s, child timestamp %s" % (parent.timestamp, child.timestamp)
use sqlalchemy events answered question.
see below self-contained flask example using in-memory sqlite database , data models (note i've changed children
class child
, relationship childs
children
.
browse 3 routes /insert_child/, /delete_child/ , /update_child/ see parent timestamp change.
from datetime import datetime flask import flask flask.ext.sqlalchemy import sqlalchemy, event app = flask(__name__) app.config['debug'] = true app.config['secret_key'] = 'super-secret' app.config['sqlalchemy_database_uri'] = 'sqlite:///:memory:' app.config['sqlalchemy_echo'] = true db = sqlalchemy(app) class parent(db.model): id = db.column(db.integer, primary_key=true) version = db.column(db.integer) timestamp = db.column(db.datetime, default=datetime.utcnow, onupdate=datetime.utcnow) children = db.relationship('child', backref='parent', lazy='dynamic', cascade="all, delete-orphan") class child(db.model): id = db.column(db.integer, primary_key=true) version = db.column(db.integer) timestamp = db.column(db.datetime, default=datetime.utcnow, onupdate=datetime.utcnow) parent_id = db.column(db.integer, db.foreignkey('parent.id'), nullable=false) @event.listens_for(parent.children, 'append') @event.listens_for(parent.children, 'remove') def receive_append_or_remove(target, value, initiator): # update when child added or removed target.timestamp = datetime.utcnow() @event.listens_for(child.version, 'set') def receive_attribute_change(target, value, oldvalue, initiator): # update when child's "version" attribute set if target.parent: target.parent.timestamp = datetime.utcnow() def render_html(): _html = "" parents = parent.query.all() parent in parents: _html += "<h4>parent : {version}; timestamp: {timestamp}</h4>".format(version=parent.version, timestamp=parent.timestamp) _html += "<ul>" child in parent.children: _html += "<li>child : {version}; timestamp: {timestamp}</li>".format(version=child.version, timestamp=child.timestamp) _html += "</ul>" return _html @app.route('/') def index(): return render_html() @app.route('/insert_child/') def insert_child(): parent = parent.query.first() child_version = parent.children.count() + 1 child = child(version=child_version, parent=parent) db.session.add(child) db.session.commit() return render_html() @app.route('/delete_child/') def delete_child(): parent = parent.query.first() if parent.children.count() > 0: last_child = parent.children[-1] parent.children.remove(last_child) db.session.commit() return render_html() @app.route('/update_child/') def update_child(): parent = parent.query.first() first_child = parent.children[0] first_child.version += 1 db.session.commit() return render_html() @app.before_first_request def before_first_request(): db.drop_all() db.create_all() parent = parent(version=1) child = child(version=1, parent=parent) db.session.add_all([parent, child]) db.session.commit() if __name__ == '__main__': app.run(debug=true)
Comments
Post a Comment