Move pk on single-inh subclass check below conflict resolution check

The column conflict resolution technique discussed at
:ref:`declarative_column_conflicts` is now functional for a :class:`.Column`
that is also a primary key column.  Previously, a check for primary key
columns declared on a single-inheritance subclass would occur before the
column copy were allowed to pass.

Fixes: #4352
Change-Id: Id4c025da53c28e58db6b549fe398f25f8a90d355
Pull-request: https://github.com/zzzeek/sqlalchemy/pull/483
(cherry picked from commit 3ed79a5c18)
This commit is contained in:
Tom Manderson
2018-10-30 13:05:43 -04:00
committed by Mike Bayer
parent 7a1c19833e
commit 6ec2246d04
4 changed files with 86 additions and 5 deletions
+10
View File
@@ -0,0 +1,10 @@
.. change::
:tags: bug, orm, declarative
:tickets: 4352
The column conflict resolution technique discussed at
:ref:`declarative_column_conflicts` is now functional for a :class:`.Column`
that is also a primary key column. Previously, a check for primary key
columns declared on a single-inheritance subclass would occur before the
column copy were allowed to pass.
+2
View File
@@ -88,6 +88,8 @@ The attribute exclusion logic is provided by the
behavior can be disabled by passing an explicit ``exclude_properties``
collection (empty or otherwise) to the ``__mapper_args__``.
.. _declarative_column_conflicts:
Resolving Column Conflicts
^^^^^^^^^^^^^^^^^^^^^^^^^^
+5 -5
View File
@@ -534,11 +534,6 @@ class _MapperConfig(object):
)
# add any columns declared here to the inherited table.
for c in declared_columns:
if c.primary_key:
raise exc.ArgumentError(
"Can't place primary key columns on an inherited "
"class with no table."
)
if c.name in inherited_table.c:
if inherited_table.c[c.name] is c:
continue
@@ -547,6 +542,11 @@ class _MapperConfig(object):
"existing column '%s'" %
(c, cls, inherited_table.c[c.name])
)
if c.primary_key:
raise exc.ArgumentError(
"Can't place primary key columns on an inherited "
"class with no table."
)
inherited_table.append_column(c)
if inherited_mapped_table is not None and \
inherited_mapped_table is not inherited_table:
+69
View File
@@ -762,6 +762,75 @@ class DeclarativeInheritanceTest(DeclarativeTestBase):
session.commit()
eq_(session.query(Engineer).first().target, o1)
def test_columns_single_inheritance_conflict_resolution_pk(self):
"""Test #2472 in terms of a primary key column. This is
#4352.
"""
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
target_id = Column(Integer, primary_key=True)
class Engineer(Person):
"""single table inheritance"""
@declared_attr
def target_id(cls):
return cls.__table__.c.get(
'target_id',
Column(Integer, primary_key=True))
class Manager(Person):
"""single table inheritance"""
@declared_attr
def target_id(cls):
return cls.__table__.c.get(
'target_id',
Column(Integer, primary_key=True))
is_(
Engineer.target_id.property.columns[0],
Person.__table__.c.target_id
)
is_(
Manager.target_id.property.columns[0],
Person.__table__.c.target_id
)
def test_columns_single_inheritance_cascading_resolution_pk(self):
"""An additional test for #4352 in terms of the requested use case.
"""
class TestBase(Base):
__abstract__ = True
@declared_attr.cascading
def id(cls):
col_val = None
if TestBase not in cls.__bases__:
col_val = cls.__table__.c.get('id')
if col_val is None:
col_val = Column(Integer, primary_key=True)
return col_val
class Person(TestBase):
"""single table base class"""
__tablename__ = 'person'
class Engineer(Person):
""" single table inheritance, no extra cols """
class Manager(Person):
""" single table inheritance, no extra cols """
is_(Engineer.id.property.columns[0], Person.__table__.c.id)
is_(Manager.id.property.columns[0], Person.__table__.c.id)
def test_joined_from_single(self):
class Company(Base, fixtures.ComparableEntity):