Skip to content

Commit

Permalink
Copies column instances to be unique per table instance.
Browse files Browse the repository at this point in the history
Fixes bug 964345.

Incidentally fixes bug 964351 as well by wrapping the dropdown
actions template code in a spaceless tag.

Change-Id: I672cb517d230db235c90a403e9b8ac0740e8732d
  • Loading branch information
gabrielhurley committed Mar 25, 2012
1 parent 28defb5 commit 52b9e19
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 13 deletions.
25 changes: 16 additions & 9 deletions horizon/tables/base.py
Expand Up @@ -617,13 +617,14 @@ def __new__(mcs, name, bases, attrs):

# 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'):
Expand Down Expand Up @@ -651,7 +652,8 @@ def __new__(mcs, name, bases, attrs):
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.
Expand Down Expand Up @@ -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():
Expand Down
2 changes: 1 addition & 1 deletion horizon/tables/views.py
Expand Up @@ -39,7 +39,7 @@ def _get_data_dict(self):

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:
Expand Down
2 changes: 2 additions & 0 deletions 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 %}
Expand All @@ -25,3 +26,4 @@
{% include "horizon/common/_data_table_row_action.html" %}
{% endfor %}
{% endif %}
{% endspaceless %}
21 changes: 18 additions & 3 deletions horizon/tests/table_tests.py
Expand Up @@ -308,9 +308,9 @@ def test_table_column(self):
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
Expand Down Expand Up @@ -552,3 +552,18 @@ def test_table_actions(self):
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))

0 comments on commit 52b9e19

Please sign in to comment.