Python 修改子表时如何更新父表时间戳?

Python 修改子表时如何更新父表时间戳?,python,sqlalchemy,flask-sqlalchemy,Python,Sqlalchemy,Flask Sqlalchemy,修改子表时,如何更新父时间戳 我想使用父表时间戳来检查我的rest客户端是否应该更新这些表的本地版本 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,

修改子表时,如何更新父时间戳

我想使用父表时间戳来检查我的rest客户端是否应该更新这些表的本地版本

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)
并对此进行测试:

    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 # this 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()
    # this fails. Parent timestamp is not updated when child is modified
    assert parent.timestamp != previous_timestamp
    print "parent timestamp: %s, child timestamp %s" % (parent.timestamp, child.timestamp)
使用SQLAlchemy来回答这个问题

请参见下面一个使用内存中SQLite数据库和数据模型的自包含烧瓶示例(注意,我已将
Children
类更改为
Child
,将
childs
关系更改为
Children

浏览到三个路由/insert\u child/、/delete\u child/和/update\u child/以查看父时间戳的更改

from datetime import datetime
from flask import Flask
from 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 a child is added or removed
    target.timestamp = datetime.utcnow()


@event.listens_for(Child.version, 'set')
def receive_attribute_change(target, value, oldvalue, initiator):
    # Update when a child's "version" attribute is set
    if target.parent:
        target.parent.timestamp = datetime.utcnow()


def render_html():
    _html = ""
    parents = Parent.query.all()
    for parent in parents:
        _html += "<h4>Parent : {version}; Timestamp: {timestamp}</h4>".format(version=parent.version, timestamp=parent.timestamp)
        _html += "<ul>"
        for 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)
从日期时间导入日期时间
从烧瓶进口烧瓶
从flask.ext.sqlalchemy导入sqlalchemy,事件
app=烧瓶(名称)
app.config['DEBUG']=True
app.config['SECRET_KEY']='super SECRET'
app.config['SQLALCHEMY\u DATABASE\u URI']='sqlite://:memory:'
app.config['SQLALCHEMY_ECHO']=True
db=SQLAlchemy(应用程序)
类父级(db.Model):
id=db.Column(db.Integer,主键=True)
version=db.Column(db.Integer)
timestamp=db.Column(db.DateTime,
默认值=datetime.utcnow,
onupdate=datetime.utcnow)
children=db.relationship('Child',
backref='parent',
“动态”,
cascade=“全部,删除孤立项”)
类子项(db.Model):
id=db.Column(db.Integer,主键=True)
version=db.Column(db.Integer)
timestamp=db.Column(db.DateTime,
默认值=datetime.utcnow,
onupdate=datetime.utcnow)
parent_id=db.Column(db.Integer,db.ForeignKey('parent.id'),nullable=False)
@event.listens_的(Parent.children,'append')
@事件。侦听(Parent.children,'remove')
def接收\附加\或\删除(目标、值、启动器):
#添加或删除子项时更新
target.timestamp=datetime.utcnow()
@事件。侦听(Child.version,'set')
def接收属性更改(目标、值、旧值、启动器):
#设置子级的“版本”属性时更新
如果target.parent:
target.parent.timestamp=datetime.utcnow()
def render_html():
_html=“”
parents=Parent.query.all()
对于家长中的家长:
_html+=“父项:{version};时间戳:{Timestamp}”。格式(version=Parent.version,Timestamp=Parent.Timestamp)
_html+=“
    ” 对于parent.children中的子项: _html+=“
  • 子项:{version};时间戳:{Timestamp}
  • ”。格式(version=Child.version,Timestamp=Child.Timestamp) _html+=“
” 返回html @应用程序路径(“/”) def index(): 返回render_html() @app.route(“/insert_child/”) def insert_child(): parent=parent.query.first() child_version=parent.children.count()+1 child=child(version=child\u version,parent=parent) db.session.add(子级) db.session.commit() 返回render_html() @app.route(“/delete_child/”) def delete_child(): parent=parent.query.first() 如果parent.children.count()大于0: last_child=父项、子项[-1] parent.children.remove(最后一个子项) db.session.commit() 返回render_html() @app.route(“/update_child/”) def update_child(): parent=parent.query.first() 第一个\u子项=父项。子项[0] 第一个子版本+=1 db.session.commit() 返回render_html() @第一次请求前的应用程序 第一次请求之前的定义() db.drop_all() db.create_all() 父项=父项(版本=1) 子=子(版本=1,父=父) db.session.add_all([parent,child]) db.session.commit() 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': app.run(debug=True)
回答得很好。这正是我想要的,谢谢!在尝试实现这一点时,我遇到了一个递归错误。任何关于如何避免的初学者友好解释,@pjcunningham?或者我需要打开一个单独的问题,因为您需要上下文?@p6l richard-需要是一个单独的问题,包括堆栈跟踪。