- edited description
inconsistency in concrete relationships w/ name overlap in relationship() vs. backref
Issue #3630
resolved
this is extracted from #3022. test:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
err = True
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
if not err:
b = relationship("B", foreign_keys="B.a_id", backref="a")
class A1(A):
__tablename__ = 'a1'
id = Column(Integer, primary_key=True)
if not err:
b = relationship("B", foreign_keys="B.a1_id", backref="a1")
__mapper_args__ = {'concrete': True}
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
a_id = Column(ForeignKey('a.id'))
a1_id = Column(ForeignKey('a1.id'))
if err:
a = relationship("A", backref="b")
a1 = relationship("A1", backref="b")
configure_mappers()
Comments (4)
-
reporter -
reporter here's a patch:
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 95aa14a..88dadcc 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1591,7 +1591,12 @@ class Mapper(InspectionAttr): if key in self._props and \ not isinstance(prop, properties.ColumnProperty) and \ - not isinstance(self._props[key], properties.ColumnProperty): + not isinstance( + self._props[key], + ( + properties.ColumnProperty, + properties.ConcreteInheritedProperty) + ): util.warn("Property %s on %s being replaced with new " "property %s; the old property will be discarded" % ( self._props[key], diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py index f822071..9b02d86 100644 --- a/lib/sqlalchemy/orm/relationships.py +++ b/lib/sqlalchemy/orm/relationships.py @@ -1817,15 +1817,16 @@ class RelationshipProperty(StrategizedProperty): backref_key, kwargs = self.backref mapper = self.mapper.primary_mapper() - check = set(mapper.iterate_to_root()).\ - union(mapper.self_and_descendants) - for m in check: - if m.has_property(backref_key): - raise sa_exc.ArgumentError( - "Error creating backref " - "'%s' on relationship '%s': property of that " - "name exists on mapper '%s'" % - (backref_key, self, m)) + if not mapper.concrete: + check = set(mapper.iterate_to_root()).\ + union(mapper.self_and_descendants) + for m in check: + if m.has_property(backref_key): + raise sa_exc.ArgumentError( + "Error creating backref " + "'%s' on relationship '%s': property of that " + "name exists on mapper '%s'" % + (backref_key, self, m)) # determine primaryjoin/secondaryjoin for the # backref. Use the one we had, so that
-
reporter - changed status to resolved
- Fixed issue where two same-named relationships that refer to
a base class and a concrete-inherited subclass would raise an error
if those relationships were set up using "backref", while setting up the
identical configuration using relationship() instead with the conflicting
names would succeed, as is allowed in the case of a concrete mapping.
fixes
#3630
→ <<cset b7bc704f3d05>>
-
reporter - the order in which _generate_backref() for different mappers is called
is random; therefore it may be called against the subclass mapper first, so
need to check .concrete on both sides, references
#3630
→ <<cset 5a279e7ae441>>
- the order in which _generate_backref() for different mappers is called
is random; therefore it may be called against the subclass mapper first, so
need to check .concrete on both sides, references
- Log in to comment