Mike,

Thanks for the response! Here is the demonstration, please let me know if 
there is something obvious that I am missing:

> cat ~/python/sq3.py
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, backref

from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))

    # association proxy of "user_keywords" collection
    # to "keyword" attribute
    keywords = association_proxy('user_keywords', 'keyword')

    def __init__(self, name):
        self.name = name

class UserKeyword(Base):
    __tablename__ = 'user_keyword'
    user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
    keyword_id = Column(Integer, ForeignKey('keyword.id'), primary_key=True)
    special_key = Column(String(50))

    # bidirectional attribute/collection of "user"/"user_keywords"
    user = relationship(User,
                backref=backref("user_keywords",
                                cascade="all, delete-orphan")
            )

    keyword = relationship("Keyword",
                backref=backref("user_keywords", cascade="all, 
delete-orphan"))

    def __init__(self, keyword=None, user=None, special_key=None):
        self.user = user
        self.keyword = keyword
        self.special_key = special_key

class Keyword(Base):
    __tablename__ = 'keyword'
    id = Column(Integer, primary_key=True)
    keyword = Column('keyword', String(64))

    users = association_proxy('user_keywords', 'user')

    def __init__(self, keyword):
        self.keyword = keyword

    def __repr__(self):
        return 'Keyword(%s)' % repr(self.keyword)

> python -i ~/python/sq3.py
>>> from sqlalchemy import create_engine
>>> from sqlalchemy.orm import Session
>>> e = create_engine("sqlite:///:memory:")
>>> Base.metadata.drop_all(e)
>>> Base.metadata.create_all(e)
>>> session=Session(e)
>>> rory=User("rory")
>>> session.add(rory)
>>> chicken=Keyword("chicken")
>>> session.add(chicken)
>>> rory.keywords.append(chicken)
>>> rory.keywords
[Keyword('chicken')]
>>> chicken.users
[<__main__.User object at 0x7f82dff87390>]
>>> rory.keywords.remove(chicken)
>>> rory.keywords
[]
>>> chicken.users
[None]
>>> session.flush()
/hostname/multiacl2/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py:235:
 
SAWarning: Object of type <UserKeyword> not in session, add operation along 
'Keyword.user_keywords' will not proceed
  (orm_util.state_class_str(state), operation, prop))
>>> chicken.user_keywords
[<__main__.UserKeyword object at 0x7f82dfa6ded0>]
>>> chicken.user_keywords[0].user
>>> chicken.user_keywords[0].keyword
Keyword('chicken')
>>>

So it definitely seems that the association object is half-disassociated. I 
have this currently worked around by setting a validator on 
UserKeyword.user that removes self from UserKeyword.keyword.user_keywords 
if self.user is None, but I am not confident in this workaround.



On Wednesday, August 24, 2016 at 1:57:58 PM UTC-4, Mike Bayer wrote:
>
>
>
> The issue mentioned in 2655 is a major behavior of the ORM, in that an 
> object is considered orphan if any of its relationships are non-present 
> in all cases, including pending and persistent, rather than if all of 
> them are un-present.     This is not at all subtle and is covered in a 
> wide range of test cases.   The test case attached to the bug continues 
> to pass, as does the demonstration attached in the migration notes: 
>
> http://docs.sqlalchemy.org/en/latest/changelog/migration_08.html#the-consideration-of-a-pending-object-as-an-orphan-has-been-made-more-aggressive.
>  
>
>          
>
> > 
> > 
> > Is anyone aware whether this bug was reintroduced on purpose (i.e. 
> > figured out the rationale for the original behavior) or by accident? 
>
> reintroduction of a bug here would need to be demonstrated. 
>

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to