Object not added to a session after assigned to a scalar part of a relationship if backref is missing

Issue #3426 closed
zifot created an issue

Not exactly sure if this is a bug, but certainly somewhat unexpected behavior.

Both of the last two assertions in the following script fail.

from sqlalchemy import (
    create_engine,
    Column,
    Integer,
    ForeignKey,
)
from sqlalchemy.orm import (
    sessionmaker,
    relationship,
    object_session,
)

from sqlalchemy.ext.declarative import declarative_base


engine = create_engine('sqlite:///test.db')
Session = sessionmaker(bind=engine)
session = Session()


Base = declarative_base()


class Parent(Base):
    __tablename__ = 'parents'

    id = Column(Integer, primary_key=True)


class Child1(Base):
    __tablename__ = 'children1'

    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey(Parent.id))
    parent = relationship(Parent, backref='children')


class Child2(Base):
    __tablename__ = 'children2'

    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey(Parent.id))
    parent = relationship(Parent)  # No backref defined


Base.metadata.create_all(engine)

parent = Parent()
session.add(parent)

child1a = Child1(parent=parent)
child1b = Child1()
child1b.parent = parent

assert object_session(child1a) is session  # True
assert object_session(child1b) is session  # True

child2a = Child2(parent=parent)
child2b = Child2()
child2b.parent = parent

assert object_session(child2a) is session  # False
assert object_session(child2b) is session  # False