]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
docs for new mixin class control abilities
authorChris Withers <chris@simplistix.co.uk>
Tue, 13 Apr 2010 15:46:07 +0000 (16:46 +0100)
committerChris Withers <chris@simplistix.co.uk>
Tue, 13 Apr 2010 15:46:07 +0000 (16:46 +0100)
doc/build/reference/ext/declarative.rst
lib/sqlalchemy/ext/declarative.py
test/ext/test_declarative.py

index 5762d03783fefda5445102709e4efe6460ef4ed8..7372f6bbefb01fcc0738b097e66d0456b97cd91c 100644 (file)
@@ -10,6 +10,8 @@ API Reference
 
 .. autofunction:: _declarative_constructor
 
+.. autofunction:: has_inherited_table
+
 .. autofunction:: synonym_for
 
 .. autofunction:: comparable_using
index 8ed83d6cd947039639524cb82cfb63bbf2e1e8f9..8a28bb07ccf1386c3b284998bf814d6059d692ce 100755 (executable)
@@ -476,6 +476,102 @@ you implement a class property with a function. For example::
 
         id =  Column(Integer, primary_key=True)
 
+Controlling table inheritance with mix-ins
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``__tablename__`` attribute in conjunction with the hierarchy of
+the classes involved controls what type of table inheritance, if any,
+is configured by the declarative extension.
+
+If the ``__tablename__`` is computed by a mix-in, you may need to
+control which classes get the computed attribute in order to get the
+type of table inheritance you require.
+
+For example, if you had a mix-in that computes ``__tablename__`` but
+where you wanted to use that mix-in in a single table inheritance
+hierarchy, you can explicitly specify ``__tablename__`` as ``None`` to
+indicate that the class should not have a table mapped::
+
+    from sqlalchemy.util import classproperty
+
+    class Tablename:
+        @classproperty
+        def __tablename__(cls):
+            return cls.__name__.lower()
+
+    class Person(Base,Tablename):
+        id = Column(Integer, primary_key=True)
+        discriminator = Column('type', String(50))
+        __mapper_args__ = {'polymorphic_on': discriminator}
+
+    class Engineer(Person):
+        __tablename__ = None
+        __mapper_args__ = {'polymorphic_identity': 'engineer'}
+        primary_language = Column(String(50))
+
+Alternatively, you can make the mix-in intelligent enough to only
+return a ``__tablename__`` in the event that no table is already
+mapped in the inheritance hierarchy. To help with this, a
+:func:`~sqlalchemy.ext.declarative.has_inherited_table` helper
+function is provided that returns ``True`` if a parent class already
+has a mapped table. 
+
+As an examply, here's a mix-in that will only allow single table
+inheritance::
+
+    from sqlalchemy.util import classproperty
+    from sqlalchemy.ext.declarative import has_inherited_table
+
+    class Tablename:
+        @classproperty
+        def __tablename__(cls):
+            if has_inherited_table(cls):
+                return None
+            return cls.__name__.lower()
+
+    class Person(Base,Tablename):
+        id = Column(Integer, primary_key=True)
+        discriminator = Column('type', String(50))
+        __mapper_args__ = {'polymorphic_on': discriminator}
+
+    class Engineer(Person):
+        __tablename__ = None
+        __mapper_args__ = {'polymorphic_identity': 'engineer'}
+        primary_language = Column(String(50))
+
+If you want to use a similar pattern with a mix of single and joined
+table inheritance, you would need a slightly different mix-in and use
+it on any joined table child classes in addition to their parent
+classes::
+
+    from sqlalchemy.util import classproperty
+    from sqlalchemy.ext.declarative import has_inherited_table
+
+    class Tablename:
+        @classproperty
+        def __tablename__(cls):
+            if (decl.has_inherited_table(cls) and
+                TableNameMixin not in cls.__bases__):
+                return None
+            return cls.__name__.lower()
+
+    class Person(Base,Tablename):
+        id = Column(Integer, primary_key=True)
+        discriminator = Column('type', String(50))
+        __mapper_args__ = {'polymorphic_on': discriminator}
+
+    class Engineer(Person):
+        # This is single table inheritance
+        __tablename__ = None
+        __mapper_args__ = {'polymorphic_identity': 'engineer'}
+        primary_language = Column(String(50))
+
+    class Manager(Person,Tablename):
+        # This is joinded table inheritance
+        __tablename__ = None
+        __mapper_args__ = {'polymorphic_identity': 'engineer'}
+        preferred_recreation = Column(String(50))
+
 Class Constructor
 =================
 
index b39be6f58bf5bda88e2879da511b390b72a19862..15799350476edb82ac418e4fbc55e11bb9ca274d 100644 (file)
@@ -2319,7 +2319,8 @@ class DeclarativeMixinTest(DeclarativeTestBase):
         class TableNameMixin:
             @classproperty
             def __tablename__(cls):
-                if decl.has_inherited_table(cls) and TableNameMixin not in cls.__bases__:
+                if (decl.has_inherited_table(cls) and
+                    TableNameMixin not in cls.__bases__):
                     return None
                 return cls.__name__.lower()