diff options
-rw-r--r-- | horizon/tables/base.py | 25 | ||||
-rw-r--r-- | horizon/tables/views.py | 2 | ||||
-rw-r--r-- | horizon/templates/horizon/common/_data_table_row_actions.html | 2 | ||||
-rw-r--r-- | horizon/tests/table_tests.py | 21 |
4 files changed, 37 insertions, 13 deletions
diff --git a/horizon/tables/base.py b/horizon/tables/base.py index ea14b1234..fc39f362d 100644 --- a/horizon/tables/base.py +++ b/horizon/tables/base.py @@ -617,13 +617,14 @@ class DataTableMetaclass(type): # Gather columns; this prevents the column from being an attribute # on the DataTable class and avoids naming conflicts. - columns = [(column_name, attrs.pop(column_name)) for - column_name, obj in attrs.items() - if issubclass(type(obj), (opts.column_class, Column))] - # add a name attribute to each column - for column_name, column in columns: - column.name = column_name + columns = [] + for name, obj in attrs.items(): + if issubclass(type(obj), (opts.column_class, Column)): + column_instance = attrs.pop(name) + column_instance.name = name + columns.append((name, column_instance)) columns.sort(key=lambda x: x[1].creation_counter) + # Iterate in reverse to preserve final order for base in bases[::-1]: if hasattr(base, 'base_columns'): @@ -651,7 +652,8 @@ class DataTableMetaclass(type): actions_column.classes.append('actions_column') actions_column.auto = "actions" columns.append(("actions", actions_column)) - attrs['columns'] = SortedDict(columns) + # Store this set of columns internally so we can copy them per-instance + attrs['_columns'] = SortedDict(columns) # Gather and register actions for later access since we only want # to instantiate them once. @@ -698,11 +700,16 @@ class DataTable(object): def __init__(self, request, data=None, **kwargs): self._meta.request = request self._meta.data = data - self._populate_data_cache() self.kwargs = kwargs - for column in self.columns.values(): + # Create a new set + columns = [] + for key, _column in self._columns.items(): + column = copy.copy(_column) column.table = self + columns.append((key, column)) + self.columns = SortedDict(columns) + self._populate_data_cache() # Associate these actions with this table for action in self.base_actions.values(): diff --git a/horizon/tables/views.py b/horizon/tables/views.py index 810118105..612afcac2 100644 --- a/horizon/tables/views.py +++ b/horizon/tables/views.py @@ -39,7 +39,7 @@ class MultiTableMixin(object): def get_tables(self): if not self.table_classes: - raise AttributeError('You must specify a one or more DataTable ' + raise AttributeError('You must specify one or more DataTable ' 'classes for the "table_classes" attribute ' 'on %s.' % self.__class__.__name__) if not self._tables: diff --git a/horizon/templates/horizon/common/_data_table_row_actions.html b/horizon/templates/horizon/common/_data_table_row_actions.html index fe223d03f..3193b69dc 100644 --- a/horizon/templates/horizon/common/_data_table_row_actions.html +++ b/horizon/templates/horizon/common/_data_table_row_actions.html @@ -1,5 +1,6 @@ {% load horizon %} +{% spaceless %} {# This makes sure whitespace doesn't affect positioning for dropdown. #} {% if row_actions|length > 1 %} <div class="btn-group"> {% for action in row_actions %} @@ -25,3 +26,4 @@ {% include "horizon/common/_data_table_row_action.html" %} {% endfor %} {% endif %} +{% endspaceless %} diff --git a/horizon/tests/table_tests.py b/horizon/tests/table_tests.py index ce5f843ba..fb50df0b1 100644 --- a/horizon/tests/table_tests.py +++ b/horizon/tests/table_tests.py @@ -308,9 +308,9 @@ class DataTableTests(test.TestCase): self.table = MyTable(self.request, TEST_DATA) row = self.table.get_rows()[0] row3 = self.table.get_rows()[2] - id_col = self.table.base_columns['id'] - name_col = self.table.base_columns['name'] - value_col = self.table.base_columns['value'] + id_col = self.table.columns['id'] + name_col = self.table.columns['name'] + value_col = self.table.columns['value'] # transform self.assertEqual(row.cells['id'].data, '1') # Standard attr access self.assertEqual(row.cells['name'].data, 'custom object_1') # Callable @@ -552,3 +552,18 @@ class DataTableTests(test.TestCase): row_actions = self.table.get_row_actions(TEST_DATA[0]) self.assertEqual(unicode(row_actions[0].verbose_name), "Delete Me") self.assertEqual(unicode(row_actions[1].verbose_name), "Log In") + + def test_column_uniqueness(self): + table1 = MyTable(self.request) + table2 = MyTable(self.request) + # Regression test for launchpad bug 964345. + self.assertNotEqual(id(table1), id(table2)) + self.assertNotEqual(id(table1.columns), id(table2.columns)) + t1cols = table1.columns.values() + t2cols = table2.columns.values() + self.assertEqual(t1cols[0].name, t2cols[0].name) + self.assertNotEqual(id(t1cols[0]), id(t2cols[0])) + self.assertNotEqual(id(t1cols[0].table), + id(t2cols[0].table)) + self.assertNotEqual(id(t1cols[0].table._data_cache), + id(t2cols[0].table._data_cache)) |