|
1 | 1 | from datetime import datetime |
2 | 2 | from pathlib import Path |
3 | | -from typing import Literal |
| 3 | +from typing import Any, Literal |
4 | 4 |
|
5 | | -from pydantic import BaseModel |
| 5 | +from pydantic import BaseModel, Field |
6 | 6 |
|
7 | 7 | from ...utils import Rating |
8 | 8 | from ..constNum import LevelItem |
@@ -40,13 +40,104 @@ class LevelRecordInfo(BaseModel): |
40 | 40 | """定数""" |
41 | 41 | rks: float = 0.0 |
42 | 42 | """等效RKS""" |
43 | | - suggest: str = "" |
| 43 | + ### 不允许序列化的字段 |
| 44 | + suggest: str = Field(default="", exclude=True) |
44 | 45 | """推分建议""" |
45 | | - num: int = 0 |
| 46 | + num: int = Field(default=0, exclude=True) |
46 | 47 | """是 Best 几""" |
47 | | - date: datetime = datetime.now() |
| 48 | + date: datetime = Field(default=datetime.now(), exclude=True) |
48 | 49 | """更新时间(iso)""" |
49 | 50 |
|
| 51 | + # 私有字段 |
| 52 | + lazy_song_id: str = Field(default="", exclude=True) |
| 53 | + lazy_index: int = Field(default=0, exclude=True) |
| 54 | + lazy_raw_data: dict[str, Any] | None = Field(default=None, exclude=True) |
| 55 | + is_lazy: bool = Field(default=False, exclude=True) |
| 56 | + initialized: bool = Field(default=True, exclude=True) # 默认为已初始化 |
| 57 | + |
| 58 | + @classmethod |
| 59 | + def lazy_init(cls, data: dict, id: str, index: int) -> "LevelRecordInfo": |
| 60 | + """ |
| 61 | + 惰性初始化方法,只设置基本字段 |
| 62 | + """ |
| 63 | + # 检查数据是否包含完整字段,如果包含则直接初始化 |
| 64 | + if cls._is_data_complete(data): |
| 65 | + # 数据已经完整,直接创建实例而不调用 init |
| 66 | + instance = cls(**data) |
| 67 | + # 标记为已初始化 |
| 68 | + instance.initialized = True |
| 69 | + instance.is_lazy = False |
| 70 | + return instance |
| 71 | + # 数据不完整,使用惰性加载 |
| 72 | + instance = cls( |
| 73 | + fc=data.get("fc", False), |
| 74 | + score=data.get("score", 0), |
| 75 | + acc=data.get("acc", 0.0), |
| 76 | + ) |
| 77 | + instance.lazy_raw_data = data |
| 78 | + instance.lazy_song_id = id |
| 79 | + instance.lazy_index = index |
| 80 | + instance.is_lazy = True |
| 81 | + instance.initialized = False |
| 82 | + return instance |
| 83 | + |
| 84 | + @classmethod |
| 85 | + def _is_data_complete(cls, data: dict) -> bool: |
| 86 | + """ |
| 87 | + 检查传入数据是否包含完整字段 |
| 88 | + """ |
| 89 | + # 定义完整字段列表 |
| 90 | + complete_fields = [ |
| 91 | + "song", |
| 92 | + "rank", |
| 93 | + "difficulty", |
| 94 | + "rks", |
| 95 | + "Rating", |
| 96 | + "illustration", |
| 97 | + ] |
| 98 | + |
| 99 | + # 检查是否包含完整字段 |
| 100 | + return all(field in data for field in complete_fields) |
| 101 | + |
| 102 | + def _ensure_initialized(self): |
| 103 | + """ |
| 104 | + 确保完全初始化 |
| 105 | + """ |
| 106 | + if not self.initialized and self.is_lazy and self.lazy_raw_data is not None: |
| 107 | + # 完整初始化 |
| 108 | + full_instance = LevelRecordInfo.init( |
| 109 | + self.lazy_raw_data, self.lazy_song_id, self.lazy_index |
| 110 | + ) |
| 111 | + # 复制所有字段 |
| 112 | + for field_name in LevelRecordInfo.model_fields: |
| 113 | + setattr(self, field_name, getattr(full_instance, field_name)) |
| 114 | + self.initialized = True |
| 115 | + self.is_lazy = False |
| 116 | + |
| 117 | + # 重写 __getattribute__ 实现惰性加载 |
| 118 | + def __getattribute__(self, name: str): |
| 119 | + # 避免无限递归,对特殊属性直接返回 |
| 120 | + if name in { |
| 121 | + "initialized", |
| 122 | + "is_lazy", |
| 123 | + "lazy_raw_data", |
| 124 | + "lazy_song_id", |
| 125 | + "lazy_index", |
| 126 | + }: |
| 127 | + return object.__getattribute__(self, name) |
| 128 | + |
| 129 | + # 检查是否是模型字段且需要初始化 |
| 130 | + if name in { |
| 131 | + "song", |
| 132 | + "rank", |
| 133 | + "difficulty", |
| 134 | + "rks", |
| 135 | + "Rating", |
| 136 | + "illustration", |
| 137 | + } and not object.__getattribute__(self, "initialized"): |
| 138 | + object.__getattribute__(self, "_ensure_initialized")() |
| 139 | + return object.__getattribute__(self, name) |
| 140 | + |
50 | 141 | @classmethod |
51 | 142 | def init(cls, data: dict, id: str, rank: int | str) -> "LevelRecordInfo": |
52 | 143 | """ |
|
0 commit comments