项目Demo地址:

https://github.com/kkjzio/Superset-By-Oauth2-with-Satoken-Demo?tab=readme-ov-file

1. 目的

有的时候使用我们需要通过前端传过来的参数来动态进行查询表中的信息,虽然superset中有筛选器的选项,但是不能指望看表单的所有人都会使用,因此本次的目的就是自定义前端信息来自定义筛选器的值。

2. 前言

  • 使用的superset版本为docker上的superset3.1.1

在使用筛选器前,应该在superset_config.py中增加下列设置,启用筛选器

#enable filters
FEATURE_FLAGS = {"DASHBOARD_FILTERS_EXPERIMENTAL": True, "DASHBOARD_NATIVE_FILTERS_SET": True, "DASHBOARD_NATIVE_FILTERS": True, "DASHBOARD_CROSS_FILTERS": True, "ENABLE_TEMPLATE_PROCESSING": True}

在使用下列方法前,需要先在面板中设置好对应的筛选器!

在使用下列方法前,需要先在面板中设置好对应的筛选器!

在使用下列方法前,需要先在面板中设置好对应的筛选器!

3. 筛选器使用

方法一:使用preselect_filters(已过时,在3版本中貌似已经不能使用了)

具体使用方法在url访问面板时使用get

/superset/dashboard/<dashboard_id or dashboard_lable>/?preselect_filters={"<chart_id>":{"<column>":["value1"]}}

比如下面的,访问第4个筛选器,然后指定筛选器的值为"blue", "yellow"

/superset/dashboard/1/?preselect_filters={"4":{"color":["blue", "yellow"]}}

方法二:使用native_filters(推荐)

该筛选器方法会在接收所有数据的基础上本地过滤数据

具体使用方法如下,在url上用get方法传参:

GET /superset/dashboard/<dashboard_id or dashboard_slug>/?native_filters=(NATIVE_FILTER-<id>:(__cache:(label:'<value>',validateStatus:!f,value:!('<value>')),extraFormData:(filters:!((col:<column>,op:<operate>,val:!('<value>')))),filterState:(label:'<value>',validateStatus:!f,value:!('<value>')),id:NATIVE_FILTER-<id>,ownState:()))
  • <id>:不同于方法一的筛选器id,这个id可以在面板->编辑->高级设置中的面板json配置文件中找到对应的NATIVE_FILTER-<id>,或者使用/api/v1/dashboard/接口查询
  • <value>:筛选器中的使用的值,可以将所有的<value>填为同一个
  • <column>:筛选器应用表的列名
  • <operate>:在数据表中的操作符,对应筛选器中的方法,可以是下面这几种

    * ==
    * !=
    * >
    * <
    * >=
    *<=
    * LIKE
    * ILIKE
    * IS NULL
    * IS NOT NULL
    * IN
    * NOT IN
    * REGEX
    * IS TRUE
    * IS FALSE

举个例子,我要查询表中videocAtegory中的为"2","3"的所有数据,那么构建的url就应该为:

native_filters=(NATIVE_FILTER-klaUNTqwp:(__cache:(label:!('2','3'),validateStatus:!f,value:!('2','3')),extraFormData:(filters:!((col:videocAtegory,op:IN,val:!('2','3')))),filterState:(label:!('2','3'),validateStatus:!f,value:!('2','3')),id:NATIVE_FILTER-klaUNTqwp,ownState:()))

以上的传输格式使用的是RISON格式,可以先在后端或者前端构建好json,转换成RISON

RISON格式更适合url传递json

RISON可以和json格式互相转换

上面例子中的原json数据为:

{"NATIVE_FILTER-klaUNTqwp":{"__cache":{"label":["2","3"],"validateStatus":false,"value":["2","3"]},"extraFormData":{"filters":[{"col":"videocAtegory","op":"IN","val":["2","3"]}]},"filterState":{"label":["2","3"],"validateStatus":false,"value":["2","3"]},"id":"NATIVE_FILTER-klaUNTqwp","ownState":{}}}

可以使用下面这两个工具处理:

方法三:使用native_filters_key

native_filters_key是一个筛选器的状态标识,可以在任何用户之间,通过native_filters_key获取到各自设定的筛选器的筛选状态,因此我们可以在后台指定一个native_filters_key,并在后台先将筛选器状态设定好然后再将其传给用户拼接url,具体流程如下:

  • 利用api先创建一个空数据状态的筛选器状态,服务器会返回一个native_filters_key

    POST`/api/v1/dashboard/{pk}/filter_state`
    • <pk>:面板的id或者是自己设定的面板SLUG
    • 请求体如下

      {"value":"{\"NATIVE_FILTER-<id1>\":{\"id\":\"NATIVE_FILTER-<id1>\",\"extraFormData\":{\"filters\":[{},\"filterState\":{},\"ownState\":{}},\"NATIVE_FILTER-<id2>\":{\"id\":\"NATIVE_FILTER-<id2>\",\"extraFormData\":{},\"filterState\":{},\"ownState\":{}}}"}
    • <id1>、<id2>为两个筛选器的id,这个id可以在面板->编辑->高级设置中的面板json配置文件中找到对应的NATIVE_FILTER-<id>,或者使用/api/v1/dashboard/接口查询
  • (可选)其中有个可选参数tab_id,若是指定该值,则会根据固定的用户信息返回固定的native_filters_key值,若是不指定,前端会自动生成tab_id

    若有需求可以看文章最后的tab_id补充
  • 得到native_filters_key后,使用这个值来选择筛选器的状态

    PUT /api/v1/dashboard/{pk}/filter_state/{native_filters_key}
    • 请求体和上面类似,只不过在上面空值的基础上填入筛选器的值,但是注意使用的是字符串形式,因此要做字符串的特殊符号转义,例如我要在NATIVE_FILTER-klaUNTqwp的筛选器中寻找值为"2","1"的数据,那么我的请求体为

      {"value":"{\"NATIVE_FILTER-klaUNTqwp\":{\"id\":\"NATIVE_FILTER-klaUNTqwp\",\"extraFormData\":{\"filters\":[{\"col\":\"videocAtegory\",\"op\":\"IN\",\"val\":[\"2\",\"1\"]}]},\"filterState\":{\"label\":\"2, 1\",\"value\":[\"2\",\"1\"]},\"ownState\":{}},\"NATIVE_FILTER-JYZ1TXNky\":{\"id\":\"NATIVE_FILTER-JYZ1TXNky\",\"extraFormData\":{},\"filterState\":{},\"ownState\":{}}}"}

      参数类似方法二中的参数,此处不做赘述。

  • 设定好筛选器后,只要在展示面板时带上该native_filters_key就可以展示筛选器的效果了,该native_filters_key不受用户角色和权限的限制

    superset/dashboard/<pk>/?native_filters_key=<native_filters_key>


4. 面板url参数,最终效果调整

我们可以利用以下url参数调整我们的面板界面:

以下 URL 参数可用于修改仪表板的呈现方式:

standalone
  • 0(默认):仪表板正常显示
  • 1:顶部导航已隐藏
  • 2:顶部导航+标题被隐藏
  • 3:隐藏顶部导航+标题+顶级选项卡
show_filters
  • 0:渲染没有过滤栏的仪表板
  • 1(默认):如果启用了本机过滤器,则使用过滤器栏渲染仪表板
expand_filters
  • (默认):如果存在本机过滤器,则渲染仪表板并展开过滤器栏
  • 0:渲染仪表板,过滤器栏折叠
  • 1:渲染仪表板并展开过滤器栏

例如,当运行本地开发版本时,以下命令将禁用顶部导航并删除过滤栏: http://localhost:8088/superset/dashboard/my-dashboard/?standalone=1&show_filters=0

再组合筛选器中的url,即可达成我们的目的

image-20240416094822107

5. 补充

关于tab_id的补充

  • 一句话总结就是随机生成一个整数后,该整数会绑定该用户的一个native_filters_key,每次的请求若是在POST/api/v1/dashboard/{pk}/filter_state和PUT/api/v1/dashboard/{pk}/filter_state/{key}上带上tab_id,则下次POST/api/v1/dashboard/{pk}/filter_state&tab_id就会用上次请求返回的native_filters_key值,而不是生成一个新的
    # superset-frontend\src\hooks\useTabId.ts
    ....
      const [tabId, setTabId] = useState<string>();
    ....
  • 生成tab_id后,前端会将其存在本地,每次访问该面板时自动调用这个固定值,除非本地使用了新的native_filters_key值,否则该值不变
  • 再来看看后台对应代码的位置

    # /superset/dashboards/filter_state/commands/update.py
    
    ....
     # Generate a new key if tab_id changes or equals 0
                contextual_key = cache_key(
                    session.get("_id"), cmd_params.tab_id, resource_id
                )
                key = cache_manager.filter_state_cache.get(contextual_key)
                if not key or not cmd_params.tab_id:
                    key = random_key()
                    cache_manager.filter_state_cache.set(contextual_key, key)
    
                new_entry: Entry = {"owner": owner, "value": value}
                cache_manager.filter_state_cache.set(cache_key(resource_id, key), new_entry)
            return key
  • 可见后台会利用登录者的信息和tab_id先去检索是否有对应的native_filters_key,若是该tab_id没有才去生成一个新的native_filters_key

6.自定义查询sql语句

建议自定义sqllab,可以参考我接下来这篇文章


reference

https://www.blef.fr/superset-filters-in-url/

https://stackoverflow.com/questions/63950646/url-filter-parameters-in-apache-superset-dashboards

https://stackoverflow.com/questions/73814452/apache-superset-how-to-customize-native-filters-in-an-url

https://sa-token.cc/doc.html#/oauth2/oauth2-interworking

https://superset.apache.org/docs/

如果对你有帮助就太好了)))