Issues

Issue #2472 resolved

provide a means of resolving single-table subclass-declared column conflicts

Mike Bayer
repo owner created an issue

this is a pseudopatch illustrating the behavior of a new method __conflicts__() which allows declared subclasses to have common columns:

diff -r 8719cf3653b9f4209a6d8e774a03cd4c5d579b8b lib/sqlalchemy/ext/declarative.py
--- a/lib/sqlalchemy/ext/declarative.py Thu Apr 19 12:31:15 2012 -0400
+++ b/lib/sqlalchemy/ext/declarative.py Fri Apr 20 06:48:32 2012 -0400
@@ -1289,6 +1289,20 @@
                         "class with no table."
                         )
                 if c.name in inherited_table.c:
+                    if hasattr(cls, '__conflicts__'):
+                        resolved = cls.__conflicts__(
+                                        # need to figure out how to get the
+                                        # mapped attribute name here
+                                        _get_the_key_for_this_column(c), 
+                                        inherited_table.c[c.name](c.name), 
+                                        c)
+                        if resolved is not None and \
+                            resolved is not inherited_table.c[c.name](c.name):
+                            # make sure this replaces the existing without
+                            # warning
+                            inherited_table.append_column(resolved)
+                            continue
+
                     raise exc.ArgumentError(
                         "Column '%s' on class %s conflicts with "
                         "existing column '%s'" %

use case is:

class Person(Base):
    __tablename__ = 'person'
    id = Column()

class Mixin(object):
    target_id = Column(ForeignKey())
    target = relationship()

    @classmethod
    def __conflicts__(cls, key, existing, new):
        return existing

class Engineer(Mixin, Person):
   """single table inheritance"""


class Manager(Mixin, Person):
   """single table inheritance"""

it has a few tricks to be worked out, namely how to we get at the attribute key there, probably need to search through our_stuff (or do a reverse lookup of our_stuff) to find it.

Comments (4)

  1. Mike Bayer reporter

    forget about __conflicts__. The attached patch implements a new approach which requires documentation:

    class Person(Base):
        __tablename__ = 'person'
        id = Column(Integer, primary_key=True)
    
    class Mixin(object):
        @declared_attr
        def target_id(cls):
            return cls.__table__.c.get('target_id',
                    Column(Integer, ForeignKey('other.id'))
                )
    
        @declared_attr
        def target(cls):
            return relationship("Other")
    
    class Engineer(Mixin, Person):
        """single table inheritance"""
    
    
    class Manager(Mixin, Person):
        """single table inheritance"""
    
  2. Log in to comment