diff --git a/gvsds/apps/gerp/form_service.py b/gvsds/apps/gerp/form_service.py index a32feb7b..9ad3e90f 100644 --- a/gvsds/apps/gerp/form_service.py +++ b/gvsds/apps/gerp/form_service.py @@ -258,179 +258,6 @@ class FormService(FormServiceBase): from gvsdsdk.auth.admin_service import IsSuperAdmin return IsSuperAdmin(user=user, role_uuid=self.current_role_uuid) - def _get_entity_picker_fields(self, model): - """获取模型中所有 entityPicker 类型的字段信息""" - result = [] - for f in model._meta.get_fields(): - if not hasattr(f, 'name'): - continue - # ForeignKey 字段 - if f.__class__.__name__ == 'ForeignKey': - try: - related_model = getattr(f, 'related_model', None) - if related_model: - related_name = related_model.__name__ - ep_config = self.ENTITY_PICKER_MAP.get(related_name) - if ep_config: - result.append({ - 'field_name': f.name, - 'label_field': ep_config['labelField'], - 'value_field': ep_config['valueField'], - 'entity_name': related_name, - 'extra_fields': ep_config.get('extraFields', []), - }) - except Exception: - pass - # UUIDField 字段(非 ForeignKey) - elif f.__class__.__name__ == 'UUIDField' and not getattr(f, 'primary_key', False): - entity_name = self.UUID_FIELD_ENTITY_MAP.get(f.name) - if entity_name: - ep_config = self.ENTITY_PICKER_MAP.get(entity_name) - if ep_config: - result.append({ - 'field_name': f.name, - 'label_field': ep_config['labelField'], - 'value_field': ep_config['valueField'], - 'entity_name': entity_name, - 'extra_fields': ep_config.get('extraFields', []), - }) - return result - - def _enrich_entity_labels(self, page_qs, ep_fields, records): - """为 records 中的 entityPicker 字段添加 _label 后缀字段,以及 extraFields - - 支持两种字段类型: - - ForeignKey:getattr(obj, field_name) 返回关联模型实例,直接取 label_field - - UUIDField:getattr(obj, field_name) 返回 UUIDObj,需批量查询关联表获取名称 - """ - try: - obj_list = list(page_qs) - except Exception: - return records - if not obj_list: - return records - - # 预构建 UUIDField 类型的 UUID → label 映射(批量查询优化性能) - # key: (entity_name, label_field), value: {uuid_bytes: label} - uuid_label_cache = {} - uuid_extra_cache = {} # key: (entity_name, extra_field), value: {uuid_bytes: value} - - for ep_info in ep_fields: - field_name = ep_info['field_name'] - entity_name = ep_info['entity_name'] - label_field = ep_info['label_field'] - extra_fields = ep_info.get('extra_fields', []) - value_field = ep_info['value_field'] - - # 判断字段类型 - field_obj = None - for f in obj_list[0]._meta.get_fields(): - if hasattr(f, 'name') and f.name == field_name: - field_obj = f - break - - # 仅对 UUIDField(非主键)类型批量查询;ForeignKey 通过 getattr 直接获取 - if not (field_obj and field_obj.__class__.__name__ == 'UUIDField' - and not getattr(field_obj, 'primary_key', False)): - continue - - # 收集所有 UUID 值(转为 bytes) - uuid_values = set() - for obj in obj_list: - val = getattr(obj, field_name, None) - if val is not None: - if hasattr(val, 'bytes'): - uuid_values.add(val.bytes) - elif isinstance(val, str): - try: - uuid_values.add(uuid.UUID(val).bytes) - except ValueError: - pass - - if not uuid_values: - continue - - related_model = self.TABLE_MAP.get(entity_name) - if not related_model: - continue - - # 批量查询关联表 - try: - related_qs = related_model.objects.filter(**{f'{value_field}__in': uuid_values}) - for r in related_qs: - pk_val = getattr(r, value_field, None) - pk_bytes = pk_val.bytes if hasattr(pk_val, 'bytes') else pk_val - if pk_bytes is None: - continue - label = getattr(r, label_field, None) - if label is not None: - uuid_label_cache.setdefault((entity_name, label_field), {})[pk_bytes] = label - for ef in extra_fields: - ef_val = getattr(r, ef, None) - if ef_val is not None: - uuid_extra_cache.setdefault((entity_name, ef), {})[pk_bytes] = ef_val - except Exception: - pass - - for i, obj in enumerate(obj_list): - if i >= len(records): - break - for ep_info in ep_fields: - field_name = ep_info['field_name'] - label_field = ep_info['label_field'] - extra_fields = ep_info.get('extra_fields', []) - entity_name = ep_info['entity_name'] - - # 判断字段类型 - field_obj = None - for f in obj._meta.get_fields(): - if hasattr(f, 'name') and f.name == field_name: - field_obj = f - break - - try: - # 获取 db_column 作为 key 前缀 - db_col = None - for f in obj._meta.get_fields(): - if hasattr(f, 'name') and f.name == field_name and hasattr(f, 'db_column'): - db_col = f.db_column or f.name - break - key_prefix = db_col or field_name - - is_uuid_field = (field_obj - and field_obj.__class__.__name__ == 'UUIDField' - and not getattr(field_obj, 'primary_key', False)) - - if is_uuid_field: - # UUIDField 类型:从缓存查找 - val = getattr(obj, field_name, None) - if val is None: - continue - val_bytes = val.bytes if hasattr(val, 'bytes') else val - if val_bytes is None: - continue - label = uuid_label_cache.get((entity_name, label_field), {}).get(val_bytes) - if label is not None: - records[i][key_prefix + '_label'] = str(label) - for ef in extra_fields: - ef_val = uuid_extra_cache.get((entity_name, ef), {}).get(val_bytes) - if ef_val is not None: - records[i][key_prefix + '_' + ef] = ef_val - else: - # ForeignKey 类型:直接获取关联实例 - related_obj = getattr(obj, field_name, None) - if related_obj is not None: - label = getattr(related_obj, label_field, None) - if label is not None: - records[i][key_prefix + '_label'] = str(label) - for ef in extra_fields: - ef_val = getattr(related_obj, ef, None) - if ef_val is not None: - records[i][key_prefix + '_' + ef] = ef_val - except Exception: - pass - return records - def get_tables(self): tables = [] for name, model in self.TABLE_MAP.items(): @@ -776,7 +603,7 @@ class FormService(FormServiceBase): # 编辑表单允许修改覆盖名(仅定制显示名,不破坏角色语义) col['editable'] = True col['hideInCreateForm'] = True - # UserRole 列表可读性:UserUUID/RoleUUID 值已由 _enrich_entity_labels 回显为 + # UserRole 列表可读性:UserUUID/RoleUUID 值已由 _EnrichEntityLabels 回显为 # 用户名/角色名,列标题直接改"用户名"/"角色名"(避免误导为裸 UUID); # CompanyUUID 为隔离冗余列,角色成员列表均按公司隔离展示,列表隐藏 if table_name == 'UserRole' and pascal_name == 'UserUUID': @@ -855,7 +682,7 @@ class FormService(FormServiceBase): col['entityPicker'] = {**col['entityPicker'], 'dependCompany': True} # UserRoleDepartment 列表可读性:UserRoleUUID 关联列列表隐藏(表单仍隐藏), # 用户/角色由下方虚拟列(UserUUID/RoleUUID)分开展示(值经 get_table 反查 UserRole 注入); - # PositionUUID 列标题改"职务"(值为职务名,由 _enrich_entity_labels 回显) + # PositionUUID 列标题改"职务"(值为职务名,由 _EnrichEntityLabels 回显) if table_name == 'UserRoleDepartment' and pascal_name == 'UserRoleUUID': col['visible'] = False if table_name == 'UserRoleDepartment' and pascal_name == 'PositionUUID': @@ -1345,7 +1172,7 @@ class FormService(FormServiceBase): start = (page - 1) * page_size # 识别 entityPicker 字段,使用 select_related 预加载关联实体 # 注意:select_related 只能用于 ForeignKey,UUIDField 类型的 entityPicker 不能预加载 - ep_fields = self._get_entity_picker_fields(model) + ep_fields = self._GetEntityPickerFields(model) if ep_fields: excluded = {'RoleUUID', 'PermUUID', 'PositionTemplateUUID', 'PositionUUID'} qs = self.ApplySelectRelated(qs, model, [ @@ -1358,7 +1185,7 @@ class FormService(FormServiceBase): records = self.BuildRecords(model, obj_list) # 为 entityPicker 字段附带关联实体的 label if ep_fields: - records = self._enrich_entity_labels(obj_list, ep_fields, records) + records = self._EnrichEntityLabels(obj_list, ep_fields, records) # UserRoleWorkgroup / UserRoleDepartment:透传关联 UserRole 的用户 UUID(前端跳转用户详情用), # 并生成 UserRoleUUID 的展示标签(label=角色名 + UserName=用户名,前端拼为"角色名(用户名)") if table_name in ('UserRoleWorkgroup', 'UserRoleDepartment'):