--- /dev/null
+.. change::
+ :tags: bug, regression, ext
+ :tickets: 6679
+
+ Fixed regression in :mod:`sqlalchemy.ext.automap` extension such that the
+ use case of creating an explicit mapped class to a table that is also the
+ :paramref:`_orm.relationship.secondary` element of a
+ :func:`_orm.relationship` that automap will be generating would emit the
+ "overlaps" warnings introduced in 1.4 and discussed at :ref:`error_qzyx`.
+ While generating this case from automap is still subject to the same
+ caveats that the "overlaps" warning refers towards, as automap is intended
+ for more ad-hoc use cases, the condition which produces the warning is
+ disabled when a many-to-many relationship with this particular pattern is
+ generated.
+
+
create_backref = backref_name not in referred_cfg.properties
+ if table in table_to_map_config:
+ overlaps = "__*"
+ else:
+ overlaps = None
+
if relationship_name not in map_config.properties:
if create_backref:
backref_obj = generate_relationship(
referred_cls,
local_cls,
collection_class=collection_class,
+ overlaps=overlaps,
)
else:
backref_obj = None
+
rel = generate_relationship(
automap_base,
interfaces.MANYTOMANY,
relationship_name,
local_cls,
referred_cls,
+ overlaps=overlaps,
secondary=table,
primaryjoin=and_(
fk.column == fk.parent for fk in m2m_const[0].elements
backref_name,
referred_cls,
local_cls,
+ overlaps=overlaps,
secondary=table,
primaryjoin=and_(
fk.column == fk.parent for fk in m2m_const[1].elements
and pr not in self.prop._reverse_property
and pr.key not in self.prop._overlaps
and self.prop.key not in pr._overlaps
+ # note: the "__*" symbol is used internally by
+ # SQLAlchemy as a general means of supressing the
+ # overlaps warning for some extension cases, however
+ # this is not currently
+ # a publicly supported symbol and may change at
+ # any time.
+ and "__*" not in self.prop._overlaps
+ and "__*" not in pr._overlaps
and not self.prop.parent.is_sibling(pr.parent)
and not self.prop.mapper.is_sibling(pr.mapper)
and not self.prop.parent.is_sibling(pr.mapper)
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import MetaData
+from sqlalchemy import select
from sqlalchemy import String
from sqlalchemy import testing
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import fixtures
+from sqlalchemy.testing import is_
from sqlalchemy.testing.mock import Mock
from sqlalchemy.testing.mock import patch
from sqlalchemy.testing.schema import Column
assert isinstance(i1.order_collection, list)
assert o1 in i1.order_collection
+ def test_m2m_relationship_also_map_the_secondary(self):
+ """test #6679"""
+
+ Base = automap_base(metadata=self.tables_test_metadata)
+
+ # extend the table to have pk cols
+ Table(
+ "order_items",
+ self.tables_test_metadata,
+ Column("item_id", None, ForeignKey("items.id"), primary_key=True),
+ Column(
+ "order_id", None, ForeignKey("orders.id"), primary_key=True
+ ),
+ extend_existing=True,
+ )
+
+ # then also map to it
+ class OrderItem(Base):
+ __tablename__ = "order_items"
+
+ Base.prepare()
+
+ Order = Base.classes["orders"]
+ Item = Base.classes["items"]
+
+ o1 = Order()
+ i1 = Item(description="x")
+ o1.items_collection.append(i1)
+
+ s = fixtures.fixture_session()
+
+ s.add(o1)
+ s.flush()
+
+ oi = s.execute(select(OrderItem)).scalars().one()
+
+ is_(oi.items, i1)
+ is_(oi.orders, o1)
+
def test_relationship_pass_params(self):
Base = automap_base(metadata=self.tables_test_metadata)