- attached bug.py
cannot add child of two parents to one parent
If a child has two parents, and one of parent attributes is set on the child, then the child cannot be added to the other parent's child relation list (the parent will not adopt the child).
version is 0.5beta3
The full example hopefully will be attached, but here is the critical part: p = DBSession.query(Parent).filter(Parent.name == u'tmp').one() p2 = DBSession.query(Parent2).filter(Parent2.name == u'tmp').one() # print p.children # uncommenting this prevents the error c = Child(name=u'the child', parent2=p2) p.children.append(c) DBSession.flush()
The p.children.append(c) raises an error that child.parent_id cannot be null (the parent did not set it's foreign key in the child).
Comments (3)
-
Account Deleted -
repo owner - changed status to wontfix
the session's autoflush is executing upon the lazyload of the p.children access, and you can see this in the stack trace generated.
Strategies to work around include:
def add_child(): p = DBSession.query(Parent).filter(Parent.name == u'tmp').one() p2 = DBSession.query(Parent2).filter(Parent2.name == u'tmp').one() # print p.children # uncommenting this prevents the error DBSession.autoflush = False c = Child(name=u'the child', parent2=p2) p.children.append(c) DBSession.flush() DBSession.autoflush = True
a @without_autoflush decorator which does the above also works, such as this one based on Pylons @decorator:
@decorator def without_autoflush(fn, self, *args, **kwargs): """Disable the Session autoflush feature for the duration of the decorated method. """ Session().autoflush=False try: return fn(self, *args, **kwargs) finally: Session().autoflush=True
also, you can fully assemble Child before accessing any collections:
c = Child(name=u'the child', parent=p, parent2=p2)
you can even disable "save-update" cascade from Parent2 to Child to delay adding the Child object:
parent_id = Column(Integer, ForeignKey("parent.id", ondelete="CASCADE"), nullable=False) parent = relation(Parent, backref=backref('children', cascade="none", order_by=id)) parent2_id = Column(Integer, ForeignKey("parent2.id", ondelete="CASCADE"), nullable=False) parent2 = relation(Parent2, backref=backref('children', order_by=id, cascade="none")) ... def add_child(): p = DBSession.query(Parent).filter(Parent.name == u'tmp').one() p2 = DBSession.query(Parent2).filter(Parent2.name == u'tmp').one() # print p.children # uncommenting this prevents the error c = Child(name=u'the child', parent2=p2) p.children.append(c) DBSession.add(c) DBSession.flush()
-
repo owner - removed milestone
Removing milestone: 0.5.0 (automated comment)
- Log in to comment
full example