]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Using @classdecorator and similar on mixins to define
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 26 Mar 2010 19:16:00 +0000 (15:16 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 26 Mar 2010 19:16:00 +0000 (15:16 -0400)
__tablename__, __table_args__, etc. now works if
the method references attributes on the ultimate
subclass. [ticket:1749]

CHANGES
lib/sqlalchemy/ext/declarative.py
test/ext/test_declarative.py

diff --git a/CHANGES b/CHANGES
index 7ad45a759cedf08f923c83b7384b476832e68304..fb0e67f9a2a7ee1b0bf62872e40cd4e5ca9ea7f2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -92,6 +92,11 @@ CHANGES
    - Using a mixin won't break if the mixin implements an 
      unpredictable __getattribute__(), i.e. Zope interfaces.
      [ticket:1746]
+
+   - Using @classdecorator and similar on mixins to define 
+     __tablename__, __table_args__, etc. now works if
+     the method references attributes on the ultimate 
+     subclass. [ticket:1749]
      
 0.6beta2
 ========
index 435d38161927fc5a361f6976046801d179c6af75..ef1d3e68c9cc9b2dbc215e7a27bac30152cb69f1 100644 (file)
@@ -531,31 +531,32 @@ def instrument_declarative(cls, registry, metadata):
     
 def _as_declarative(cls, classname, dict_):
 
-    # doing it this way enables these attributes to be descriptors,
-    # see below...
-    get_mapper_args = '__mapper_args__' in dict_
-    get_table_args = '__table_args__' in dict_
-    
     # dict_ will be a dictproxy, which we can't write to, and we need to!
     dict_ = dict(dict_)
 
     column_copies = dict()
-
+    unmapped_mixins = False
     for base in cls.__bases__:
         names = dir(base)
         if not _is_mapped_class(base):
+            unmapped_mixins = True
             for name in names:
                 obj = getattr(base,name, None)
                 if isinstance(obj, Column):
                     dict_[name]=column_copies[obj]=obj.copy()
-            get_mapper_args = get_mapper_args or getattr(base,'__mapper_args__',None)
-            get_table_args = get_table_args or getattr(base,'__table_args__',None)
-            tablename = getattr(base,'__tablename__',None)
-            if tablename:
-                # subtle: if tablename is a descriptor here, we actually
-                # put the wrong value in, but it serves as a marker to get
-                # the right value value...
-                dict_['__tablename__']=tablename
+
+    # doing it this way enables these attributes to be descriptors
+    get_mapper_args = '__mapper_args__' in dict_
+    get_table_args = '__table_args__' in dict_
+    if unmapped_mixins:
+        get_mapper_args = get_mapper_args or getattr(cls,'__mapper_args__',None)
+        get_table_args = get_table_args or getattr(cls,'__table_args__',None)
+        tablename = getattr(cls,'__tablename__',None)
+        if tablename:
+            # subtle: if tablename is a descriptor here, we actually
+            # put the wrong value in, but it serves as a marker to get
+            # the right value value...
+            dict_['__tablename__']=tablename
 
     # now that we know whether or not to get these, get them from the class
     # if we should, enabling them to be decorators
index fbe47ee7fce03d1d2702ba50b80d9b8ee0fd6cc0..bfc3ab074d21bc133869451230c0bfb410a74a56 100644 (file)
@@ -1958,6 +1958,18 @@ class DeclarativeMixinTest(DeclarativeTestBase):
 
         eq_(MyModel.__table__.name,'mymodel1')
     
+    def test_table_name_dependent_on_subclass(self):
+        class MyHistoryMixin:
+            @classproperty
+            def __tablename__(cls):
+                return cls.parent_name + '_changelog'
+
+        class MyModel(Base, MyHistoryMixin):
+            parent_name = 'foo'
+            id = Column(Integer, primary_key=True)
+            
+        eq_(MyModel.__table__.name, 'foo_changelog')
+        
     def test_table_args_inherited(self):
         
         class MyMixin: