Pandas DataFrame逐行对比两列词列表并高亮差异实现方法
账户访问权限审计功能的权限列差异高亮实现方案
需求说明
基于Neo4j数据源开发账户间访问权限审计功能,需要逐行对比DataFrame中存储权限列表的两列单元格不对,哦,正常写:
需求背景
开发基于Neo4j数据源的账户间访问权限审计功能,需逐行对比DataFrame中存储权限列表的两列单元格内容,高亮展示同组两个用户的权限差异项。
示例数据结构如下:
ID| User A | ROLES | Rights | SOME INFO | USER B| ROLES | RIGHTS ----------------------------------------------------------------- 1 | titi | Reader|[a,b,d] | blalbalbla| toto | writer|[c,d,f,a] ------------------------------------------------------------------ 2 | tata | Manage|[b,f,g] | blalblalba| tutu | Reader|[a,b,d]
对比规则为逐行匹配同组用户权限:第一行比对titi和toto的权限、第二行比对tata和tutu的权限,将两边不一致的权限项做高亮标记。
现有代码
当前已完成基础表格渲染逻辑,代码如下:
def _render_results(self, queries): num_queries = len(queries) # For each selected query for counter, q in enumerate(queries, 1): # Print result if q['result']: df = pandas.DataFrame(q['result']) # Replace header df = df[1:] df.columns = q['headers'] # Table settings pandas.set_option('display.max_rows', 500000) pandas.set_option('display.max_colwidth', 0) display(df) else: self.printmd("No Results !")
当前仅通过display函数直接输出原生表格,未实现差异对比和高亮逻辑,以下是可直接落地的实现方案。
实现步骤
- 第一步:统一权限列格式
先兼容权限列的两种存储格式:如果是[a,b,d]形式的字符串就解析为列表,如果是原生Python列表就直接使用,避免格式问题导致对比出错。 - 第二步:逐行计算权限差集
逐行遍历两个权限列,通过集合运算分别算出A用户独有、B用户独有的权限项,给差异项包裹带背景色的HTML标签,共有权限保持普通文本。 - 第三步:渲染带样式的表格
替换原有直接输出原生DataFrame的逻辑,使用pandas Styler渲染表格,关闭HTML转义保证高亮标签生效。
改造后可直接复用的代码
import pandas as pd def _highlight_diff_permissions(row, col_a, col_b): # 解析权限值为集合,兼容字符串列表、原生列表两种格式 def _parse_perm(val): if isinstance(val, str): val = val.strip('[]').split(',') val = [v.strip() for v in val if v.strip()] return set(val) if val else set() perm_a = _parse_perm(row[col_a]) perm_b = _parse_perm(row[col_b]) # 计算两边独有的权限 a_only = perm_a - perm_b b_only = perm_b - perm_a # 生成A列带高亮标签的内容 a_rendered = [] for p in perm_a: if p in a_only: # 红色标记A独有权限 a_rendered.append(f'<span style="background-color: #ff6b6b; color: #fff; padding: 1px 3px; border-radius: 3px;">{p}</span>') else: a_rendered.append(p) # 生成B列带高亮标签的内容 b_rendered = [] for p in perm_b: if p in b_only: # 蓝色标记B独有权限 b_rendered.append(f'<span style="background-color: #4dabf7; color: #fff; padding: 1px 3px; border-radius: 3px;">{p}</span>') else: b_rendered.append(p) row_res = row.copy() row_res[col_a] = '[' + ','.join(a_rendered) + ']' row_res[col_b] = '[' + ','.join(b_rendered) + ']' return row_res def _render_results(self, queries): # 配置需要对比的两个权限列名,和实际表头保持一致即可 PERM_COL_A = "Rights" PERM_COL_B = "RIGHTS" for counter, q in enumerate(queries, 1): if q['result']: df = pd.DataFrame(q['result']) df = df[1:] df.columns = q['headers'] pd.set_option('display.max_rows', 500000) pd.set_option('display.max_colwidth', 0) # 逐行处理权限列,添加高亮标签 df = df.apply(lambda x: _highlight_diff_permissions(x, PERM_COL_A, PERM_COL_B), axis=1) # 渲染带HTML样式的表格,关闭转义保证标签生效 styler = df.style.hide(axis='index').format(escape=False).set_table_styles([ {'selector': 'td', 'props': 'padding: 8px; font-size: 14px; text-align: left;'} ]) display(styler) else: self.printmd("No Results !")
效果说明
- 红色高亮为A用户持有、B用户未持有的权限
- 蓝色高亮为B用户持有、A用户未持有的权限
- 双方共有的权限保持普通文本样式无高亮
- 可直接修改代码中
background-color的色值调整高亮配色。
内容的提问来源于stack exchange,提问作者MathRig
相关产品推荐
相关产品推荐

