""" 字段业务模型 定义字段的数据结构和业务逻辑 """ from dataclasses import dataclass, field from datetime import datetime from typing import Optional, List from config import FieldType @dataclass class Field: """ 字段模型类 Attributes: id: 字段ID full_name: 完整名称(如 gis.map.location) domain: 域名(如 gis) sub_domains: 子域列表(如 ['map']) name: 字段名(如 location) type: 字段类型 range_min: 最小值 range_max: 最大值 default_value: 默认值 unit: 单位 description: 描述信息 created_time: 创建时间 updated_time: 更新时间 """ full_name: str domain: str name: str type: FieldType id: Optional[int] = None sub_domains: Optional[List[str]] = field(default_factory=list) range_min: Optional[str] = None range_max: Optional[str] = None default_value: Optional[str] = None unit: Optional[str] = None description: Optional[str] = None created_time: Optional[datetime] = None updated_time: Optional[datetime] = None def __post_init__(self): """初始化后处理""" # 确保type是FieldType枚举 if isinstance(self.type, str): self.type = FieldType(self.type) # 从full_name解析domain、sub_domains和name if self.full_name and not self.domain: self._parse_full_name() def _parse_full_name(self): """从完整名称解析域、子域和字段名""" parts = self.full_name.split('.') if len(parts) >= 2: self.domain = parts[0] self.name = parts[-1] if len(parts) > 2: self.sub_domains = parts[1:-1] elif len(parts) == 1: self.domain = "default" self.name = parts[0] @staticmethod def build_full_name(domain: str, name: str, sub_domains: Optional[List[str]] = None) -> str: """ 构建完整字段名 Args: domain: 域名 name: 字段名 sub_domains: 子域列表 Returns: 完整字段名 """ parts = [domain] if sub_domains: parts.extend(sub_domains) parts.append(name) return '.'.join(parts) def get_sub_domains_str(self) -> str: """获取子域的字符串表示(用于数据库存储)""" if self.sub_domains: return '.'.join(self.sub_domains) return '' @staticmethod def parse_sub_domains(sub_domains_str: str) -> List[str]: """解析子域字符串""" if sub_domains_str: return sub_domains_str.split('.') return [] def validate(self) -> tuple[bool, str]: """ 验证字段数据的有效性 Returns: (是否有效, 错误信息) """ if not self.full_name: return False, "字段完整名称不能为空" if not self.domain: return False, "字段域不能为空" if not self.name: return False, "字段名不能为空" if not self.type: return False, "字段类型不能为空" # 验证范围值 if self.range_min and self.range_max: try: if self.type in [FieldType.INT, FieldType.FLOAT, FieldType.DOUBLE]: min_val = float(self.range_min) max_val = float(self.range_max) if min_val > max_val: return False, "最小值不能大于最大值" except ValueError: return False, "范围值格式不正确" return True, "" def to_dict(self) -> dict: """转换为字典""" return { 'id': self.id, 'full_name': self.full_name, 'domain': self.domain, 'sub_domains': self.get_sub_domains_str(), 'name': self.name, 'type': self.type.value if isinstance(self.type, FieldType) else self.type, 'range_min': self.range_min, 'range_max': self.range_max, 'default_value': self.default_value, 'unit': self.unit, 'description': self.description, 'created_time': self.created_time.isoformat() if self.created_time else None, 'updated_time': self.updated_time.isoformat() if self.updated_time else None, } @classmethod def from_dict(cls, data: dict) -> 'Field': """从字典创建对象""" # 解析子域 sub_domains_str = data.get('sub_domains', '') sub_domains = cls.parse_sub_domains(sub_domains_str) if sub_domains_str else [] # 解析时间 created_time = None if data.get('created_time'): if isinstance(data['created_time'], str): created_time = datetime.fromisoformat(data['created_time']) else: created_time = data['created_time'] updated_time = None if data.get('updated_time'): if isinstance(data['updated_time'], str): updated_time = datetime.fromisoformat(data['updated_time']) else: updated_time = data['updated_time'] return cls( id=data.get('id'), full_name=data['full_name'], domain=data['domain'], sub_domains=sub_domains, name=data['name'], type=data['type'], range_min=data.get('range_min'), range_max=data.get('range_max'), default_value=data.get('default_value'), unit=data.get('unit'), description=data.get('description'), created_time=created_time, updated_time=updated_time, ) def __str__(self) -> str: """字符串表示""" return f"Field(id={self.id}, full_name={self.full_name}, type={self.type.value})" def __repr__(self) -> str: """详细字符串表示""" return self.__str__()