From 261f0ecafd927b151f4b4ef06aaac5c059878c79 Mon Sep 17 00:00:00 2001 From: Luiz Otavio <45200344+luizotavio32@users.noreply.github.com> Date: Thu, 30 Apr 2026 08:40:16 -0300 Subject: [PATCH] fix(drill-to-detail): drill to detail by correctly filtering by metric (#39766) Co-authored-by: Michael S. Molina (cherry picked from commit df396aa6e9d6614c33d432c072ae1920475d33bc) --- superset/models/helpers.py | 8 +++++ tests/unit_tests/models/helpers_test.py | 46 +++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/superset/models/helpers.py b/superset/models/helpers.py index 71958d8cf83..3364e589fd4 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -3024,6 +3024,14 @@ class ExploreMixin: # pylint: disable=too-many-public-methods else: # Check if it's a regular column first col_obj = columns_by_name.get(cast(str, flt_col)) + if col_obj is None: + # Fall back to verbose_name so filters produced by + # right-click "Drill to detail by" (which can pass a + # column's verbose label) still resolve to a real column. + col_obj = next( + (c for c in self.columns if c.verbose_name == flt_col), + None, + ) # If not found in columns, check if it's a metric # This supports filtering on metric columns for any chart type if ( diff --git a/tests/unit_tests/models/helpers_test.py b/tests/unit_tests/models/helpers_test.py index 6a423d5f828..c2a32416c2e 100644 --- a/tests/unit_tests/models/helpers_test.py +++ b/tests/unit_tests/models/helpers_test.py @@ -1965,3 +1965,49 @@ def test_adhoc_column_type_probe_uses_limit_1_for_row_dependent_engines( assert not any(p in probe_sql for p in always_false_patterns), ( f"Row-dependent engines: probe must NOT use WHERE false, got: {probe_sql}" ) + + +def test_filter_by_verbose_name_resolves_to_column( + database: Database, +) -> None: + """ + A filter whose "col" value matches a column's verbose_name + (e.g. the label emitted by "Drill to detail by") must resolve to that + column and produce a WHERE clause on the underlying column_name. + """ + from superset.connectors.sqla.models import SqlaTable, TableColumn + + table = SqlaTable( + database=database, + schema=None, + table_name="t", + columns=[ + TableColumn( + column_name="country_code", + verbose_name="Country", + type="TEXT", + ), + TableColumn(column_name="b", type="TEXT"), + ], + ) + + sqla_query = table.get_sqla_query( + columns=["b"], + # Filter uses the verbose label, as "Drill to detail by" does. + filter=[{"col": "Country", "op": "==", "val": "US"}], + is_timeseries=False, + row_limit=10, + ) + + with database.get_sqla_engine() as engine: + sql = str( + sqla_query.sqla_query.compile( + dialect=engine.dialect, + compile_kwargs={"literal_binds": True}, + ) + ) + + # The filter should be translated to a WHERE clause on the real column. + assert "WHERE" in sql, f"Expected WHERE clause, got SQL: {sql}" + assert "country_code" in sql, f"Expected filter on 'country_code', got SQL: {sql}" + assert "'US'" in sql, f"Expected filter value 'US', got SQL: {sql}"