import random import string from hashlib import md5 from typing import Any, Dict, List, Union, Optional, get_origin, get_args, Type from pydantic import BaseModel def gen_random_str(length=10, prefix="", suffix=""): """ 生成随机字符串,默认长度为10,可添加前缀和后缀 """ random_str = prefix + ''.join(random.choices(string.ascii_letters + string.digits, k=length)) + suffix return md5(random_str.encode()).hexdigest() def split_generator(iterable, chunk_size=50): """ 将可迭代对象拆分为多个子列表 """ chunk = [] for item in iterable: chunk.append(item) if len(chunk) == chunk_size: yield chunk chunk = [] if chunk: yield chunk async def async_split_generator(iterable, chunk_size=50): """ 将可迭代对象拆分为多个子列表 """ chunk = [] async for item in iterable: chunk.append(item) if len(chunk) == chunk_size: yield chunk chunk = [] if chunk: yield chunk async def async_generator_to_list(iterable): """ 将可迭代对象转换为列表 """ return [item async for item in iterable] TYPE_MAPPING = { "str": "string", "int": "number", "float": "number", "bool": "boolean", "list": "array", "dict": "object", "NoneType": "null", # 注意:None 的类型名是 'NoneType' } def transform_pydantic_to_list( cls: Type[BaseModel], prefix: str = "" # 新增:当前路径前缀 ) -> List[Dict[str, Any]]: if not issubclass(cls, BaseModel): raise TypeError(f"{cls} is not a Pydantic BaseModel") result = [] exclude_filter = getattr(cls, "__exclude_filter__", []) meta_mapping = getattr(cls, "__meta_mapping__", {}) for field_name, field_info in cls.model_fields.items(): if field_name in exclude_filter: continue # 构建当前字段的完整路径 current_path = f"{prefix}.{field_name}" if prefix else field_name field_meta = meta_mapping.get(field_name, {}) or {} raw_type = field_info.annotation children = [] display_type_name = "any" origin = get_origin(raw_type) args = get_args(raw_type) # 处理 Optional[T](即 Union[T, None]) if origin is Union and type(None) in args: # 提取非 None 的类型 non_none_types = [arg for arg in args if arg is not type(None)] if len(non_none_types) == 1: inner_type = non_none_types[0] else: inner_type = raw_type # 多类型 Union,暂不深入处理 else: inner_type = raw_type # 判断是否为 List[BaseModel] list_origin = get_origin(inner_type) if list_origin is list: item_type = get_args(inner_type)[0] if get_args(inner_type) else Any if isinstance(item_type, type) and issubclass(item_type, BaseModel): children = transform_pydantic_to_list(item_type, prefix=current_path) display_type_name = "list" elif isinstance(inner_type, type) and issubclass(inner_type, BaseModel): children = transform_pydantic_to_list(inner_type, prefix=current_path) display_type_name = "object" else: # 基础类型:获取类型名 if inner_type is type(None): display_type_name = "NoneType" elif hasattr(inner_type, '__name__'): display_type_name = inner_type.__name__ else: display_type_name = str(inner_type) frontend_type = TYPE_MAPPING.get(display_type_name, "string") item = { "value": current_path, # ✅ 使用层级路径 "label": field_info.description or field_name, "type": frontend_type, **field_meta, } if children: item["children"] = children result.append(item) return result if __name__ == "__main__": print(gen_random_str()) print(gen_random_str()) print(gen_random_str()) print(gen_random_str())