- changed status to duplicate
Can't set to None relationship property of object being in collection of collections
Test case:
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class DocLink(Base):
__tablename__ = 'DocLink'
id = Column(Integer, primary_key=True)
block_id = Column(ForeignKey('DocLinkBlock.id', ondelete='CASCADE'),
nullable=False)
block = relationship('DocLinkBlock',
primaryjoin='DocLink.block_id==DocLinkBlock.id')
ref_url = Column(String(250), nullable=True)
ref_doc_id = Column(ForeignKey('Doc.id'))
ref_doc = relationship('Doc', primaryjoin='DocLink.ref_doc_id==Doc.id')
class DocLinkBlock(Base):
__tablename__ = 'DocLinkBlock'
id = Column(Integer, primary_key=True)
doc_id = Column(ForeignKey('Doc.id', ondelete='CASCADE'), nullable=False)
doc = relationship('Doc')
links = relationship(DocLink, cascade='all, delete-orphan')
class Doc(Base):
__tablename__ = 'Doc'
id = Column(Integer, primary_key=True)
link_blocks = relationship(DocLinkBlock, cascade='all, delete-orphan')
engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()
ref_doc = Doc(id=1)
session.add(ref_doc)
session.commit()
doc = Doc(
id=2,
link_blocks=[
DocLinkBlock(
id=1,
links=[
DocLink(
id=1,
ref_url='url',
ref_doc=ref_doc,
),
],
),
],
)
session.add(doc)
session.commit()
assert doc.link_blocks[0].links[0].ref_url=='url'
assert doc.link_blocks[0].links[0].ref_doc is ref_doc
doc.link_blocks = [
DocLinkBlock(
id=1,
links=[
DocLink(
id=1,
ref_url=None,
ref_doc=None,
),
],
),
]
session.commit()
assert doc.link_blocks[0].links[0].ref_url is None
assert doc.link_blocks[0].links[0].ref_doc is None # Fails
There is no such problem when DocLinkBlock.links
is updated directly (no nested collections).
Comments (8)
-
repo owner -
repo owner you already reported this in
#3060, and it's already fixed! make sure you try master next time, thanks. -
reporter Tried with 912ebaa8b02f05d6148e5a3c5194fa9d2b3dc36a and it still doesn't work, while test case reported in
#3060works. -
repo owner it works with bc08ee902925, that's the cset that fixes the issue. 912ebaa8b02f05d is on the 0.9 branch.
-
repo owner the reason you're hitting these issues is because these patterns rely heavily on an edge case called "row switch". when you have a relationship A->B(1), and then you just stick a totally different B(1) onto A and rely upon delete-cascade to take out the old B(1), the ORM turns the DELETE + INSERT into an UPDATE. You'd be better off avoiding this pattern, and just modifying the existing B(1) instead, either by loading it or using merge(). the patterns here look a lot like trying to avoid using merge().
-
repo owner it's not really saving you on any SQL here either, the old row is loaded, so merge() would do a get() and just pull it up.
-
reporter This code is a simplified from what is generated from DSL for web forms. Fields in forms can be arbitrary nested. Convertion of field in form must not have side effect, so it can't call merge for object (at least untill all other fields are verified).
-
reporter Yes, it works with master, thanks!
- Log in to comment
Duplicate of
#3060.