Superset實現動態SQL查詢


使用自定義參數方式實現 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中的應用,可以實現動態查詢,解決一些無法通過頁面直接交互查詢結果顯示的內容

另外如果你有其他應用或者自定義上的思考,歡迎留言,相互學習

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM