SIT/models/field.py

195 lines
6.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
字段业务模型
定义字段的数据结构和业务逻辑
"""
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__()