data_filter作为filterjson逻辑表达式,提取var构造搜索表单

This commit is contained in:
Hermes Agent 2026-06-22 14:43:33 +08:00
parent b4ac434b62
commit f00d95654c
2 changed files with 65 additions and 37 deletions

View File

@ -73,8 +73,7 @@ data_browser_tmpl = """
{% if content_view %}
"content_view":{{json.dumps(content_view, indent=4, ensure_ascii=False)}},
{% endif %}
{% if search_fields %}
"search_fields":{{json.dumps(search_fields, indent=4, ensure_ascii=False)}},
{% if data_filter %}
"search_form":{
"css":"card",
"padding":"8px",
@ -157,30 +156,14 @@ ns['sort'] = '{{relation.outter_field}}_text'
{% endif %}
sql = '''{{sql}}'''
{% if not relation %}
filterjson = params_kw.get('data_filter')
if filterjson and isinstance(filterjson, str):
try:
filterjson = json.loads(filterjson)
except (json.JSONDecodeError, TypeError):
filterjson = None
{% if data_filter %}
filterjson = {{json.dumps(data_filter, ensure_ascii=False)}}
{% else %}
filterjson = None
fields_str=r'''{{json.dumps(fields, indent=4, ensure_ascii=False)}}'''
ori_fields = json.loads(fields_str)
if not filterjson:
fields = [ f['name'] for f in ori_fields ]
filterjson = default_filterjson(fields, ns)
{% if search_fields %}
# 应用 search_fields 中显式声明的 op如 LIKE
__sf_ops = {f['field']: f.get('op') for f in {{json.dumps(search_fields, ensure_ascii=False)}} if f.get('op')}
if filterjson and __sf_ops:
if not isinstance(filterjson, dict) or 'AND' not in filterjson:
filterjson = {'AND': [filterjson] if filterjson else []}
for fj in filterjson['AND']:
if fj.get('field') in __sf_ops:
fj['op'] = __sf_ops[fj['field']]
if fj['op'] == 'LIKE':
var = fj.get('var')
if var and var in ns and ns[var]:
ns[var] = f'%{ns[var]}%'
fields = [ f['name'] for f in ori_fields ]
filterjson = default_filterjson(fields, ns)
{% endif %}
{% if logined_userorgid or logined_userid %}
# 确保 logined 过滤条件始终生效

View File

@ -255,50 +255,95 @@ def filter_backslash(s):
ls = s.split('\\/')
return '/'.join(ls)
def extract_filter_vars(filterjson, field_map):
"""递归提取 data_filter 中的 var 和对应的 field返回 {var: field_info}"""
if not filterjson:
return {}
result = {}
if isinstance(filterjson, dict):
# 逻辑操作符AND, OR, NOT
for key in ['AND', 'OR', 'NOT', 'and', 'or', 'not']:
if key in filterjson:
sub = filterjson[key]
if isinstance(sub, list):
for item in sub:
result.update(extract_filter_vars(item, field_map))
elif isinstance(sub, dict):
result.update(extract_filter_vars(sub, field_map))
# 单个条件field + op + var
if 'field' in filterjson and 'var' in filterjson:
var_name = filterjson['var']
field_name = filterjson['field']
if field_name in field_map:
result[var_name] = field_map[field_name].copy()
elif isinstance(filterjson, list):
for item in filterjson:
result.update(extract_filter_vars(item, field_map))
return result
def build_filter_field_list(desc) -> list:
"""Build enriched filter field list for InlineForm search form.
When a search_fields field has uitype='code', auto-populate
valueField/textField/params/dataurl from the model's codes definition."""
if not desc.search_fields:
"""从 data_filter 提取所有 var根据 field 从 fields/alters 获取字段定义,
构造 InlineForm 搜索字段field name var"""
if not desc.data_filter:
return []
# 构建 field name -> field info 的映射
field_map = {}
for f in field_list(desc):
field_map[f['name']] = f
# 从 data_filter 提取 var -> field info
var_field_map = extract_filter_vars(desc.data_filter, field_map)
codes_map = {}
if desc.codes:
for c in desc.codes:
cfield = c.field if isinstance(c, dict) else getattr(c, 'field', None)
if cfield:
codes_map[cfield] = c
modulename = getattr(desc, 'modulename', '')
result = []
for f in desc.search_fields:
field_name = f.field if isinstance(f, dict) else getattr(f, 'field', '')
field_title = f.title if isinstance(f, dict) else getattr(f, 'title', '')
field_uitype = f.uitype if isinstance(f, dict) else getattr(f, 'uitype', 'str')
for var_name, field_info in var_field_map.items():
field_name = field_info['name']
field_title = field_info.get('title', field_name)
field_uitype = field_info.get('uitype', 'str')
field_def = {
'name': field_name,
'name': var_name,
'uitype': field_uitype,
'placeholder': field_title,
'cwidth': 15
}
if field_uitype == 'code' and field_name in codes_map:
c = codes_map[field_name]
ctable = c.table if isinstance(c, dict) else getattr(c, 'table', '')
cvaluefield = c.valuefield if isinstance(c, dict) else getattr(c, 'valuefield', '')
ctextfield = c.textfield if isinstance(c, dict) else getattr(c, 'textfield', '')
ccond = (c.cond if isinstance(c, dict) else getattr(c, 'cond', None))
field_def['valueField'] = field_name
field_def['textField'] = field_name + '_text'
field_def['valueField'] = var_name
field_def['textField'] = var_name + '_text'
field_def['params'] = {
'dbname': "{{get_module_dbname('" + modulename + "')}}",
'table': ctable,
'tblvalue': cvaluefield,
'tbltext': ctextfield,
'valueField': field_name,
'textField': field_name + '_text'
'valueField': var_name,
'textField': var_name + '_text'
}
if ccond:
field_def['params']['cond'] = ccond
field_def['dataurl'] = "{{entire_url('/appbase/get_code.dspy')}}?prepend_all=1"
result.append(field_def)
return result
def build_data_browser(pat: str, desc: dict):