使用自定义参数方式实现 superset 实现SQL动态查询

1、启用参数:config.py 设置"ENABLE_TEMPLATE_PROCESSING": True

2、当前superset v1.2版本支持的参数包括:

{{ current_username() }}     当前登录用户名
{{ current_username(add_to_cache_keys=False) }}   不从缓存中获取登录用户名,默认从缓存获取
{{ current_user_id()}}    当前登录用户ID
{{ current_user_id(add_to_cache_keys=False) }}  不从缓存中获取登录用户ID,默认从缓存获取
{{ url_param('custom_variable') }} url 参数,比如127.0.0.1:8001\dashboard?abc=123,参数就是{{ url_param('abc') }}  结果就是123
{{ cache_key_wrapper() }}   还没有弄明白啥用
{{ filter_values("字段名") }}  获取dashboard filter_box组件对某个字段的筛选结果
{{ from_dttm }}  获取dashboard filter_box组件日期筛选的开始时间
{{ to_dttm }}   获取dashboard filter_box组件日期筛选的结束时间
{{ get_filters() }}  暂时没有弄明白

除此之外,还可以自定义参数,自定义参数方法:

①修改superset/jinja_context.py文件,修改三个地方:

 1 regex = re.compile(
2 r"\{\{.*("
3 r"current_user_id\(.*\)|"
4 r"current_username\(.*\)|"
5 r"current_userroles\(.*\)|"
6 r"isadmin\(.*\)|"
7 r"cache_key_wrapper\(.*\)|"
8 r"url_param\(.*\)"
9 r").*\}\}"
10 )

↑↑↑↑注意此处的 current_userroles 和 isadmin 是我自定义的,源文件没有

 1     def current_user_id(self, add_to_cache_keys: bool = True) -> Optional[int]:
2 """
3 Return the user ID of the user who is currently logged in.
4
5 :param add_to_cache_keys: Whether the value should be included in the cache key
6 :returns: The user ID
7 """
8
9 if hasattr(g, "user") and g.user:
10 if add_to_cache_keys:
11 self.cache_key_wrapper(g.user.get_id())
12 return g.user.get_id()
13 return None
14
15 def current_username(self, add_to_cache_keys: bool = True) -> Optional[str]:
16 """
17 Return the username of the user who is currently logged in.
18
19 :param add_to_cache_keys: Whether the value should be included in the cache key
20 :returns: The username
21 """
22
23 if g.user and hasattr(g.user, "username"):
24 if add_to_cache_keys:
25 self.cache_key_wrapper(g.user.username)
26 return g.user.username
27 return None
28 def current_userroles(self, add_to_cache_keys: bool = True) -> Optional[str]:
29 """
30 Return the roles of the user who is currently logged in.
31
32 :param add_to_cache_keys: Whether the value should be included in the cache key
33 :returns: The userroles
34 """
35
36 if g.user and hasattr(g.user, "roles"):
37 if add_to_cache_keys:
38 user_roles = "/".join([role.name.lower() for role in list(g.user.roles)])
39 self.cache_key_wrapper(user_roles)
40 print(user_roles)
41 return user_roles
42 """admin in user_roles"""
43 return None
44
45 def isadmin(self, add_to_cache_keys: bool = True) -> Optional[str]:
46 """
47 Return the roles of the user who is currently logged in.
48
49 :param add_to_cache_keys: Whether the value should be included in the cache key
50 :returns: The userroles
51 """
52
53 if g.user and hasattr(g.user, "roles"):
54 if add_to_cache_keys:
55 user_roles = [role.name.lower() for role in list(g.user.roles)]
56 return "admin" in user_roles
57 return None

↑↑↑↑仿照系统自带的 current_username 编造自己的函数,我写了current_userroles 和 isadmin

 1 class JinjaTemplateProcessor(BaseTemplateProcessor):
2 def set_context(self, **kwargs: Any) -> None:
3 super().set_context(**kwargs)
4 extra_cache = ExtraCache(self._extra_cache_keys)
5 self._context.update(
6 {
7 "url_param": partial(safe_proxy, extra_cache.url_param),
8 "current_user_id": partial(safe_proxy, extra_cache.current_user_id),
9 "current_username": partial(safe_proxy, extra_cache.current_username),
10 "current_userroles": partial(safe_proxy, extra_cache.current_userroles),
11 "isadmin": partial(safe_proxy, extra_cache.isadmin),
12 "cache_key_wrapper": partial(safe_proxy, extra_cache.cache_key_wrapper),
13 "filter_values": partial(safe_proxy, filter_values),
14 }
15 )

↑↑↑↑仿照系统自带的 current_username 编造自己的函数,我写了current_userroles 和 isadmin

就是这3个地方,但是注意,自己在第二步早的函数,返回值必须是:

 1 ALLOWED_TYPES = (
2 NONE_TYPE,
3 "bool",
4 "str",
5 "unicode",
6 "int",
7 "long",
8 "float",
9 "list",
10 "dict",
11 "tuple",
12 "set",
13 )

否则会提示错误,或者自己修改这个types,我是转换,比如上面那个g.user.roles 返回的结果就不是上面类型,导致我一直不成功,最后修改了下,才可以

3、判断是否自定义成功:

在superset sql lab中执行如下代码,如果能被解析,就说明成功

4、应用案例:

在dataset里面,动态访问数据源,数据源添加where语句:select * from sales where salesname =' {{current_username()}}'

dashboard里面,通过获取筛选器的结果,然后获取其他表应当显示的数据范围:

 1 select  DATE,risktype,sum(num) as num from
2 (SELECT date , customerid,product,risktype ,count(*) as num
3 from v_superset_forecast_risk group by date , customerid,product,risktype ) a
4 join
5 (select distinct customer_code,product from v_superset_access
6 where name='{{ current_username() }}' )access
7 on a.customerid=access.customer_code
8 and a.product=access.product
9 and DATE_FORMAT(date,'%Y-%m')> DATE_FORMAT(date_sub(STR_TO_DATE(concat( {{ "'" + "', '".join(filter_values('yearmonthend')) + "'" }},'-01'), '%Y-%m-%d'), interval 12 month),'%Y-%m')
10 and DATE_FORMAT(date,'%Y-%m')<={{ "'" + "', '".join(filter_values('yearmonthend')) + "'" }}
11 group by DATE,risktype

因为sql里面可以使用jinja 表达式,比如判断筛选当前没有筛选的时候,获取什么数据

1 {% if isadmin() %}
2
3 select * from sales
4
5 {% else %}
6
7 select * from sales where name ='{{current_username()}}'
8
9 {% endif %}

注意{%   %} 内部使用参数的时候,不需要加{{}},否则报错

通过筛选器实现模糊查询

 5、官方参考文档:https://superset.apache.org/docs/installation/sql-templating

官方没有那么详细,但是里面有一些我这里可能也没有消化吸收掉,可以参考看下

总之,通过上面的自定义参数方法,和jinja表达式在sql中的应用,可以实现动态查询,解决一些无法通过页面直接交互查询结果显示的内容

另外如果你有其他应用或者自定义上的思考,欢迎留言,相互学习

Superset实现动态SQL查询的更多相关文章

  1. SQL Server-聚焦深入理解动态SQL查询(三十二)

    前言 之前有园友一直关注着我快点出SQL Server性能优化系列,博主我也对性能优化系列也有点小期待,本来打算利用周末写死锁以及避免死锁系列的接着进入SQL Server优化系列,但是在工作中长时间 ...

  2. SQL Server-聚焦sp_executesql执行动态SQL查询性能真的比exec好?

    前言 之前我们已经讨论过动态SQL查询呢?这里为何再来探讨一番呢?因为其中还是存在一定问题,如标题所言,很多面试题也好或者有些博客也好都在说在执行动态SQL查询时sp_executesql的性能比ex ...

  3. 一步步学Mybatis-怎么样实现动态SQL查询(6)

    上一章我们已经讲完了关于Mybatis的分页用法,其实MyBatis 还具有的一个强大的特性之一通常是它的动态 SQL 能力. 如果你有使用 JDBC 或其他 相似框架的经验,你就明白要动态的串联 S ...

  4. 获取动态SQL查询语句返回值(sp_executesql)

    在写存储过程时经常会遇到需要拼接SQL语句的情况,一般情况下仅仅是为了执行拼接后的语句使用exec(@sql)即可. 而今天的一个存储过程却需要获取动态SQL的查询结果. 需求描述:在某表中根据Id值 ...

  5. SQL Server 2012 - 动态SQL查询

    动态SQL的两种执行方式:EXEC @sql 和 EXEC sys.sp_executesql @sql DECLARE @c_ids VARCHAR(200) SET @c_ids ='1,2' - ...

  6. Mybatis中多个参数的问题&&动态SQL&&查询结果与类的对应

    ### 1. 抽象方法中多个参数的问题 在使用MyBatis时,接口中的抽象方法只允许有1个参数,如果有多个参数,例如: Integer updatePassword( Integer id, Str ...

  7. ibatis 中动态SQL查询和动态标签嵌套的使用

    ibatis 动态查询对于从事 Java EE 的开发人员来说,iBatis 是一个再熟悉不过的持久层框架了,在 Hibernate.JPA 这样的一站式对象 / 关系映射(O/R Mapping)解 ...

  8. mybatis 动态SQL查询总结

    背景 ××项目需要提供系统部分函数第三方调用接口,基于安全性和避免暴露数据库表信息的基础上进行函数接口的设计,根据第三方调用身份的权限提供某张表的自定义集合.本项目基于mybatis的持久层框架,支持 ...

  9. MyBatis 动态SQL查询,多条件,分页

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-/ ...

  10. SpringBoot中JPA使用动态SQL查询

    https://www.jianshu.com/p/f72d82e90948 可以重点关注方法二,把原生sql传入数据库去查询 好处是:更加灵活坏处是:拼接sql比较痛苦,也容易出问题,比如拼接的sq ...

随机推荐

  1. macOS安装使用OpenConnect客户端替代cisco连接公司内网环境

    mac_os安装openconnect服务 brew install openconnect 使用OpenConnect客户端拨通VPN,打开终端执行以下命令: sudo openconnect -u ...

  2. ABP发布后通过外部URL调用不到方法

    MVC要与Host项目发布保持同步,如果Host工程不保持同步就会导致调用不到新的方法,因为找不得新的dll.

  3. CAD Plus 移动端使用帮助

    Mac端使用帮助 English help 如果您有疑问或需要帮助请发送邮件至 3167292926@qq.com 1. 权限要求 1.1 获取位置信息 使用文件管理功能时显示网络信息需要获取位置信息 ...

  4. NZOJ 模拟赛8

    T1 布尔(CF2030C) CF2030C 爱丽丝和鲍勃正在玩一个游戏.游戏中有一个由 n 个布尔值组成的列表,每个布尔值要么为真,要么为假,以长度为 n 的二进制字符串表示(其中 1 表示为真,0 ...

  5. 连接数据库报错的异常可以用mysqli_report来捕获

    有时候数据库密码改了或者数据库删了,就会有一个mysqli的链接报错,是因为直接使用了类似代码 $connection = new mysqli('127.0.0.1', 'test_user', ' ...

  6. 2024-11-27:字符串的分数。用go语言,给定一个字符串 s,我们可以定义其“分数”为相邻字符的 ASCII 码差值绝对值的总和。 请计算并返回字符串 s 的分数。 输入:s = “hello“

    2024-11-27:字符串的分数.用go语言,给定一个字符串 s,我们可以定义其"分数"为相邻字符的 ASCII 码差值绝对值的总和. 请计算并返回字符串 s 的分数. 输入:s ...

  7. 为什么Spring官方不推荐使用 @Autowired?

    前言 很多人刚接触 Spring 的时候,对 @Autowired 绝对是爱得深沉. 一个注解,轻松搞定依赖注入,连代码量都省了. 谁不爱呢? 但慢慢地,尤其是跑到稍微复杂点的项目里,@Autowir ...

  8. S2P销讯通-SFE人才对企业管理层至关重要

    SFE这一概念,最初由外资企业引入,如今已逐渐被内资企业所采纳并融入其组织结构中,不少企业正积极构建这一部门. 1 我们观察到,近两年企业内对于SFE部门所需的人才需求急剧上升.这一部门,在外资企业中 ...

  9. Git clone报错“Connection was reset, errno 10054”

    前情 最近在使用一个UI库的时候,发现其中一个BUG,于是想尝试提一个PR. 坑位 我平时习惯用https的方式拉取代码,发现在clone代码的时候一直失败,错误提示:OpenSSL SSL_read ...

  10. COSBrowser iOS 版 | 如何不打开 App 查看监控数据?

    您是否有遇到这样的场景?当需要实时查看存储监控数据.查看某个存储桶的对象数量,又或者想了解某一个存储类型文件的下载量在当前与前一天的对比情况,是上涨了还是下降了,这时您是否也在经历频繁的打开关闭 Ap ...