Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort lists in exported dashboards #224

Merged
merged 1 commit into from
Jul 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions superset/superset/connectors/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ class BaseColumn(AuditMixinNullable, ImportMixin):

# [optional] Set this to support import/export functionality
export_fields = []
export_ordering = 'column_name'

def __repr__(self):
return self.column_name
Expand Down Expand Up @@ -419,6 +420,8 @@ class BaseMetric(AuditMixinNullable, ImportMixin):
d3format = Column(String(128))
warning_text = Column(Text)

export_ordering = 'metric_name'

"""
The interface should also declare a datasource relationship pointing
to a derivative of BaseDatasource, along with a FK
Expand Down
1 change: 1 addition & 0 deletions superset/superset/connectors/sqla/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ class SqlaTable(Model, BaseDatasource):
f for f in export_fields if f not in ('table_name', 'database_id')]
export_parent = 'database'
export_children = ['metrics', 'columns']
export_ordering = 'table_name'

sqla_aggregations = {
'COUNT_DISTINCT': lambda column_name: sa.func.COUNT(sa.distinct(column_name)),
Expand Down
8 changes: 7 additions & 1 deletion superset/superset/models/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,8 @@ def export_dashboards(cls, dashboard_ids):
)
# remove ids and relations (like owners, created by, slices, ...)
copied_dashboard = dashboard.copy()
for slc in dashboard.slices:
sorted_slices = sorted(dashboard.slices, key=lambda x: (x.slice_name or ''))
for slc in sorted_slices:
datasource_ids.add((slc.datasource_id, slc.datasource_type))
copied_slc = slc.copy()
# save original id into json
Expand Down Expand Up @@ -685,6 +686,11 @@ def export_dashboards(cls, dashboard_ids):
datasource_class = copied_datasource.__class__
for field_name in datasource_class.export_children:
field_val = getattr(eager_datasource, field_name).copy()
sort_by = None
if len(field_val) > 0:
sort_by = field_val[0].export_ordering
if sort_by:
field_val = sorted(field_val, key=lambda x: getattr(x, sort_by))
# set children without creating ORM relations
copied_datasource.__dict__[field_name] = field_val
eager_datasources.append(copied_datasource)
Expand Down
23 changes: 17 additions & 6 deletions superset/superset/models/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ class ImportMixin(object):
# The names of the attributes
# that are available for import and export

# If a collection is exported, this str represents by which argument
# to sort the collection achieve a deterministic order.
# Deterministic ordering is useful for diffing and unit tests
export_ordering = None

@classmethod
def _parent_foreign_key_mappings(cls):
"""Get a mapping of foreign name to the local name of foreign keys"""
Expand Down Expand Up @@ -203,16 +208,22 @@ def export_to_dict(self, recursive=True, include_parent_ref=False,
}
if recursive:
for c in self.export_children:
# sorting to make lists of children stable
dict_rep[c] = sorted(
[
sort_by = None
orm_children = getattr(self, c)
children = []
if orm_children:
children = [
child.export_to_dict(
recursive=recursive,
include_parent_ref=include_parent_ref,
include_defaults=include_defaults,
) for child in getattr(self, c)
],
key=lambda k: sorted(k.items()))
) for child in orm_children
]
sort_by = orm_children[0].export_ordering
# sorting to make lists of children stable
if sort_by:
children = sorted(children, key=lambda x: x.get(sort_by))
dict_rep[c] = children

return dict_rep

Expand Down