是否可以在SQLAlchemy中创建可以创建父记录的事件侦听器?

时间:2014-01-25 00:05:05

标签: python sqlalchemy

有两个表:父母和孩子。我想创建一个事件监听器(“触发器”),如果子级没有父级,则可以创建父级。

这就是我试图做的事情:

class parent(db.Model):
    __tablename__ = 'parent'
    id = db.Column(db.Integer, primary_key=True)
    children = db.relationship("child", backref="parent",
                               cascade="all, delete-orphan",
                               passive_deletes=True)


class child(db.Model):
    __tablename__ = 'child'
    id = db.Column(db.Integer, primary_key=True)
    parent_id = db.Column(db.Integer,
                          db.ForeignKey('parent.id', ondelete='CASCADE'),
                          nullable=False)


def create_parent(mapper, connection, target):
    if not(target.parent):
         target.parent = parent()

event.listen(child, 'before_insert', create_parent)     

测试:

c = child()
db.session.add(c)
db.session.commit()

并收到以下警告和错误:

C:\Python27\x\lib\site-packages\sqlalchemy\orm\unitofwork.py:79: SAWarning: Usage of the 'related attribute set' operation is not currently supported within the execution stage of the flush process. Results may not be consistent.  Consider using alternative event listeners or connection-level operations instead.
  sess._flush_warning("related attribute set")

C:\Python27\x\lib\site-packages\sqlalchemy\orm\unitofwork.py:37: SAWarning: Usage of the 'collection append' operation is not currently supported within the execution stage of the flush process. Results may not be consistent.  Consider using alternative event listeners or connection-level operations instead.
  sess._flush_warning("collection append")

sqlalchemy.exc.IntegrityError: (IntegrityError) null value in column "parent_id" violates not-null constraint
DETAIL:  Failing row contains (1, null).
 'INSERT INTO child (parent_id) VALUES (%(parent_id)s) RETURNING child.id' {'parent_id': None}

我在文档中发现,使用before_insert事件无法实现这一点,但使用before_flush,但我不知道如何做到这一点。

1 个答案:

答案 0 :(得分:2)

与此同时,我找到了解决这个问题的方法。

from sqlalchemy.orm.session import Session as SessionBase

def before_flush(session, flush_context, instances):
    children = [c for c in session.new if isinstance(c, child)]
    for c in children:
        if not (c.parent):
            c.parent = parent()

event.listen(SessionBase, "before_flush", before_flush)

如果有人发现这不是处理此方案的正确方法,我将非常感谢您的评论。