mirror of
https://github.com/apache/superset.git
synced 2026-05-21 15:55:10 +00:00
fix(subdirectory): avoid explore redirect loop when form_data has no datasource
CI 25898464041 (Python-Integration, postgres + mysql) failed
`test_slices` and `test_slice_id_is_always_logged_correctly_on_web_request`
with werkzeug.test.ClientRedirectError: Loop detected: A 302 redirect to
/explore/?slice_id=216&form_data={"slice_id": 216} was already made.
`Slice.slice_url` builds /explore/?slice_id=X&form_data={"slice_id": X},
i.e. no datasource. The ExploreView.root redirect added in d8335c0e1b
fires unconditionally when form_data is present, but
Superset.get_redirect_url() only rewrites the URL when
parsed_form_data["datasource"] exists (the form_data → form_data_key
caching path is gated on a datasource). Without one, the redirect target
equals the source and the test client follows itself in circles.
Fix: pre-parse form_data and only delegate to get_redirect_url when a
datasource is present; otherwise fall through to render_app_template.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ from flask_appbuilder.security.decorators import has_access
|
||||
|
||||
from superset import event_logger
|
||||
from superset.superset_typing import FlaskResponse
|
||||
from superset.views.utils import loads_request_json
|
||||
|
||||
from .base import BaseSupersetView
|
||||
|
||||
@@ -37,11 +38,20 @@ class ExploreView(BaseSupersetView):
|
||||
# After `Superset.route_base = ""`, both `Superset.explore` and this
|
||||
# view register at `/explore/`; this view wins. Preserve the legacy
|
||||
# form_data → form_data_key cache-and-redirect contract here so
|
||||
# callers passing `?form_data=...` still get the short cache-key URL.
|
||||
if request.args.get("form_data"):
|
||||
from superset.views.core import Superset # avoid circular import
|
||||
# callers passing `?form_data=...` with a datasource still get the
|
||||
# short cache-key URL. Form_data without a datasource (e.g. legacy
|
||||
# `slice_url` payloads carrying only `slice_id`) cannot be cached,
|
||||
# so `get_redirect_url` would return the same URL — falling back to
|
||||
# SPA rendering avoids a 302 loop.
|
||||
if request_form_data := request.args.get("form_data"):
|
||||
try:
|
||||
parsed_form_data = loads_request_json(request_form_data)
|
||||
except ValueError:
|
||||
parsed_form_data = {}
|
||||
if parsed_form_data.get("datasource"):
|
||||
from superset.views.core import Superset # avoid circular import
|
||||
|
||||
return redirect(Superset.get_redirect_url())
|
||||
return redirect(Superset.get_redirect_url())
|
||||
return super().render_app_template()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user