# 数据结构字典 (/zh/docs/guide/data-model)

Astrolabe、Palace、Star、Horoscope 每一个字段的类型与含义。



*适合：开发者*

这一页以序列化后的 JSON 字段名（camelCase）为准，它是三套绑定共用的契约。
各编程语言的命名换算：

| 层           | 命名               | 示例               |
| ----------- | ---------------- | ---------------- |
| JSON / 绑定契约 | camelCase        | `isBodyPalace`   |
| Python      | snake\_case      | `is_body_palace` |
| Go          | PascalCase       | `IsBodyPalace`   |
| Rust        | snake\_case，值为枚举 | `is_body_palace` |

## Astrolabe 星盘 [#astrolabe-星盘]

排盘入口的返回值。

| 字段                             | 类型                          | 含义                        |
| ------------------------------ | --------------------------- | ------------------------- |
| `gender`                       | string                      | 性别，翻译文本                   |
| `genderKey`                    | string                      | `"male"` / `"female"`     |
| `solarDate`                    | string                      | 阳历生日，与入参一致                |
| `lunarDate`                    | string                      | 农历生日的文字表示                 |
| `chineseDate`                  | string                      | 四柱干支展示串                   |
| `rawDates`                     | [RawDates](#rawdates-结构化日期) | 结构化的农历生日与四柱               |
| `time`                         | string                      | 时辰名，如「寅时」                 |
| `timeRange`                    | string                      | 时辰时间段，如「03:00\~05:00」     |
| `sign`                         | string                      | 星座                        |
| `signKey`                      | string                      | 星座 key，`aries` … `pisces` |
| `zodiac`                       | string                      | 生肖，按年支                    |
| `zodiacKey`                    | string                      | 生肖 key，`rat` … `pig`      |
| `earthlyBranchOfSoulPalace`    | string                      | 命宫地支                      |
| `earthlyBranchOfSoulPalaceKey` | string                      | 命宫地支 key                  |
| `earthlyBranchOfBodyPalace`    | string                      | 身宫地支                      |
| `earthlyBranchOfBodyPalaceKey` | string                      | 身宫地支 key                  |
| `soul`                         | string                      | 命主星                       |
| `soulKey`                      | string                      | 命主星 key                   |
| `body`                         | string                      | 身主星                       |
| `bodyKey`                      | string                      | 身主星 key                   |
| `fiveElementsClass`            | string                      | 五行局                       |
| `fiveElementsClassKey`         | string                      | 五行局 key，如 `water2nd`      |
| `palaces`                      | [Palace](#palace-宫位)\[12]   | 十二宫，索引 0 是寅宫              |
| `timeIndex`                    | int                         | 出生时辰索引 0–12，保留原始传入值       |
| `fixLeap`                      | bool                        | 是否修正闰月                    |
| `language`                     | string                      | 盘面语言                      |
| `config`                       | [Config](#config-配置)        | 排盘配置                      |

## Palace 宫位 [#palace-宫位]

| 字段                                 | 类型                     | 含义                                                                           |
| ---------------------------------- | ---------------------- | ---------------------------------------------------------------------------- |
| `index`                            | int                    | 宫位在盘上的位置，0–11，0 是寅宫                                                          |
| `name`                             | string                 | 宫名                                                                           |
| `nameKey`                          | string                 | 宫名 key，如 `soulPalace`                                                        |
| `isBodyPalace`                     | bool                   | 是否身宫                                                                         |
| `isOriginalPalace`                 | bool                   | 是否来因宫                                                                        |
| `heavenlyStem`                     | string                 | 宫干                                                                           |
| `heavenlyStemKey`                  | string                 | 宫干 key                                                                       |
| `earthlyBranch`                    | string                 | 宫支                                                                           |
| `earthlyBranchKey`                 | string                 | 宫支 key                                                                       |
| `majorStars`                       | [Star](#star-星耀)\[]    | 主星                                                                           |
| `minorStars`                       | [Star](#star-星耀)\[]    | 辅星                                                                           |
| `adjectiveStars`                   | [Star](#star-星耀)\[]    | 杂耀                                                                           |
| `changsheng12` / `changsheng12Key` | string                 | 长生十二神                                                                        |
| `boshi12` / `boshi12Key`           | string                 | 博士十二神                                                                        |
| `jiangqian12` / `jiangqian12Key`   | string                 | 将前十二神                                                                        |
| `suiqian12` / `suiqian12Key`       | string                 | 岁前十二神                                                                        |
| `mutagenStarKeys`                  | string\[4]             | 本宫宫干化出的四颗星标识，顺序为禄、权、科、忌；受[自定义四化表](/zh/docs/guide/guides/config#自定义四化表与亮度表)影响 |
| `decadal`                          | [Decadal](#decadal-大限) | 该宫掌管的大限                                                                      |
| `ages`                             | int\[]                 | 小限经过该宫的虚岁列表                                                                  |

## Star 星耀 [#star-星耀]

| 字段              | 类型      | 含义                                                                                  |
| --------------- | ------- | ----------------------------------------------------------------------------------- |
| `key`           | string  | 星耀 key，如 `ziweiMaj`                                                                 |
| `name`          | string  | 星名                                                                                  |
| `type`          | string  | `major` / `soft` / `tough` / `adjective` / `flower` / `helper` / `lucun` / `tianma` |
| `scope`         | string  | `origin` / `decadal` / `yearly` / `monthly` / `daily` / `hourly`                    |
| `brightness`    | string  | 亮度显示文本。**主星与辅星恒有这个键**，无亮度时为空串；杂耀与流耀整个键缺省                                            |
| `brightnessKey` | string? | 亮度标识。无亮度时**缺省**（不是空串）                                                               |
| `mutagen`       | string  | 四化显示文本。**十四主星与左辅右弼文昌文曲这 18 颗四化候选星恒有这个键**，无四化时为空串；其余星整个键缺省                           |
| `mutagenKey`    | string? | 四化标识。无四化时**缺省**                                                                     |

<Callout type="warn" title="翻译字段与标识字段的缺省规则相反">
  `brightness` / `mutagen` 这两个**翻译字段**按星耀类别决定键在不在，
  在的时候可能是空串；`brightnessKey` / `mutagenKey` 这两个**标识字段**
  则是没值就整个键不出现。

  所以「有没有亮度」要判断 `brightnessKey` 存在与否，
  而不是判断 `brightness` 这个键在不在 —— 后者对所有主辅星都为真。
</Callout>

## Decadal 大限 [#decadal-大限]

| 字段                                   | 类型          | 含义       |
| ------------------------------------ | ----------- | -------- |
| `range`                              | \[int, int] | 起止虚岁，含两端 |
| `heavenlyStem` / `heavenlyStemKey`   | string      | 大限天干     |
| `earthlyBranch` / `earthlyBranchKey` | string      | 大限地支     |

## RawDates 结构化日期 [#rawdates-结构化日期]

| 字段                        | 类型                | 含义                                        |
| ------------------------- | ----------------- | ----------------------------------------- |
| `lunarDate.lunarYear`     | int               | 农历年                                       |
| `lunarDate.lunarMonth`    | int               | 农历月 1–12                                  |
| `lunarDate.lunarDay`      | int               | 农历日 1–30                                  |
| `lunarDate.isLeap`        | bool              | 是否闰月                                      |
| `chineseDate.yearly`      | \[string, string] | 年柱 \[天干, 地支]                              |
| `chineseDate.monthly`     | \[string, string] | 月柱                                        |
| `chineseDate.daily`       | \[string, string] | 日柱                                        |
| `chineseDate.hourly`      | \[string, string] | 时柱                                        |
| `chineseDate.yearlyKeys`  | \[string, string] | 年柱的[语言无关 key](/zh/docs/guide/guides/keys) |
| `chineseDate.monthlyKeys` | \[string, string] | 月柱的语言无关 key                               |
| `chineseDate.dailyKeys`   | \[string, string] | 日柱的语言无关 key                               |
| `chineseDate.hourlyKeys`  | \[string, string] | 时柱的语言无关 key                               |

四柱里的干支是未本地化的原文（任何盘面语言下都是中文），做判断请用 `*Keys`。
把 `*Keys` 交给 `translate_chinese_date` 即可得到按语言翻译的展示串，
与顶层 `chineseDate` 字段逐字一致。

## Config 配置 [#config-配置]

| 字段                | 取值                           | 默认        |
| ----------------- | ---------------------------- | --------- |
| `yearDivide`      | `normal` / `exact`           | `normal`  |
| `horoscopeDivide` | `normal` / `exact`           | `normal`  |
| `ageDivide`       | `normal` / `birthday`        | `normal`  |
| `dayDivide`       | `forward` / `current`        | `forward` |
| `algorithm`       | `default` / `zhongzhou`      | `default` |
| `astroType`       | `heaven` / `earth` / `human` | `heaven`  |

另有两个**只进不出**的输入键，用于替换内置数据表：

| 输入键          | 取值                                       |
| ------------ | ---------------------------------------- |
| `mutagens`   | `{天干标识: [四个星耀标识]}`，顺序为禄权科忌，必须四项          |
| `brightness` | `{星耀标识: [十二个亮度标识]}`，第一项是寅宫，必须十二项，无亮度处传空串 |

<Callout type="warn">
  这两个键**不会回显在星盘的 `config` 里** —— 它们是排盘的输入配置，
  不属于排盘结果，加进 DTO 会破坏与 JS iztro 的字段契约。
  要留档就自己存那份配置。
</Callout>

含义见 [Config 详解](/zh/docs/guide/guides/config)。

## Horoscope 运限 [#horoscope-运限]

| 字段          | 类型                                     | 含义                   |
| ----------- | -------------------------------------- | -------------------- |
| `solarDate` | string                                 | 目标阳历日期               |
| `lunarDate` | string                                 | 目标农历日期               |
| `decadal`   | [HoroscopeScope](#horoscopescope-运限层级) | 大限，未起运时为童限           |
| `age`       | HoroscopeScope                         | 小限，带 `nominalAge`    |
| `yearly`    | HoroscopeScope                         | 流年，带 `yearlyDecStar` |
| `monthly`   | HoroscopeScope                         | 流月                   |
| `daily`     | HoroscopeScope                         | 流日                   |
| `hourly`    | HoroscopeScope                         | 流时                   |

### HoroscopeScope 运限层级 [#horoscopescope-运限层级]

| 字段                                   | 类型                                     | 含义                                                                                     |
| ------------------------------------ | -------------------------------------- | -------------------------------------------------------------------------------------- |
| `index`                              | int                                    | 该运限所在盘上位置 0–11                                                                         |
| `name`                               | string                                 | 层级名，翻译文本                                                                               |
| `nameKey`                            | string                                 | 层级 key：`decadal` / `childhood` / `turn`（小限）/ `yearly` / `monthly` / `daily` / `hourly` |
| `heavenlyStem` / `heavenlyStemKey`   | string                                 | 该运限天干                                                                                  |
| `earthlyBranch` / `earthlyBranchKey` | string                                 | 该运限地支                                                                                  |
| `palaceNames`                        | string\[12]                            | 以该运限位置为命宫重排的宫名，按盘上位置排列                                                                 |
| `palaceNameKeys`                     | string\[12]                            | 同上的 key 形式                                                                             |
| `mutagen`                            | string\[4]                             | 四化星名，顺序为禄、权、科、忌                                                                        |
| `mutagenStarKeys`                    | string\[4]                             | 同上的 key 形式，与宫位的同名字段同义——被化的四颗星的星耀标识；单数 `mutagenKey` 才是四化类型（`sihuaLu` 等）                 |
| `stars`                              | [Star](#star-星耀)\[]\[12]?              | 流耀在十二宫的分布（外层十二项对应宫位，内层是该宫的流耀列表），无流耀的层级缺省                                               |
| `nominalAge`                         | int?                                   | 虚岁，仅小限有                                                                                |
| `yearlyDecStar`                      | [YearlyDecStar](#yearlydecstar-流年十二神)? | 仅流年有                                                                                   |

<Callout type="warn" title="大限层未起运时 nameKey 是 childhood">
  命主尚未起运时，`decadal` 这一层的 `nameKey` 为 `childhood`（童限）而非 `decadal`——
  童限与大限是不同的解盘语义。程序判断该层是不是童限请用 `nameKey`，
  不要比对 `name` 的译文。
</Callout>

### YearlyDecStar 流年十二神 [#yearlydecstar-流年十二神]

| 字段                                | 类型          | 含义                  |
| --------------------------------- | ----------- | ------------------- |
| `suiqian12` / `suiqian12Keys`     | string\[12] | 按流年支起的岁前十二神，索引即宫位索引 |
| `jiangqian12` / `jiangqian12Keys` | string\[12] | 按流年支起的将前十二神         |

<Callout title="Rust 侧的 base 层">
  Rust 里 `age` 与 `yearly` 的通用字段收在 `.base` 下（`AgeItem { base, nominal_age }`），
  序列化时用 `#[serde(flatten)]` 展平，所以 JSON 与 Python / Go 侧看到的是平铺结构。
</Callout>

## 完整 JSON 样例 [#完整-json-样例]

`by_solar("2000-8-16", 2, female)` 的真实输出（顶层，省略 `palaces` 的十二项）：

```json
{
  "gender": "女",
  "genderKey": "female",
  "solarDate": "2000-8-16",
  "lunarDate": "二〇〇〇年七月十七",
  "chineseDate": "庚辰 甲申 丙午 庚寅",
  "rawDates": {
    "lunarDate": { "lunarYear": 2000, "lunarMonth": 7, "lunarDay": 17, "isLeap": false },
    "chineseDate": {
      "yearly": ["庚", "辰"], "monthly": ["甲", "申"],
      "daily": ["丙", "午"], "hourly": ["庚", "寅"],
      "yearlyKeys": ["gengHeavenly", "chenEarthly"],
      "monthlyKeys": ["jiaHeavenly", "shenEarthly"],
      "dailyKeys": ["bingHeavenly", "wuEarthly"],
      "hourlyKeys": ["gengHeavenly", "yinEarthly"]
    }
  },
  "time": "寅时",
  "timeRange": "03:00~05:00",
  "sign": "狮子座", "signKey": "leo",
  "zodiac": "龙", "zodiacKey": "dragon",
  "earthlyBranchOfSoulPalace": "午", "earthlyBranchOfSoulPalaceKey": "wuEarthly",
  "earthlyBranchOfBodyPalace": "戌", "earthlyBranchOfBodyPalaceKey": "xuEarthly",
  "soul": "破军", "soulKey": "pojunMaj",
  "body": "文昌", "bodyKey": "wenchangMin",
  "fiveElementsClass": "木三局", "fiveElementsClassKey": "wood3rd",
  "palaces": [ /* 12 项 */ ],
  "timeIndex": 2,
  "fixLeap": true,
  "language": "zh-CN",
  "config": {
    "yearDivide": "normal", "horoscopeDivide": "normal",
    "ageDivide": "normal", "dayDivide": "forward",
    "algorithm": "default", "astroType": "heaven"
  }
}
```

### 一个宫的样例 [#一个宫的样例]

同一张盘的命宫（`palaces` 里 `index` 为 4 的那一项）：

```json
{
  "index": 4,
  "name": "命宫", "nameKey": "soulPalace",
  "isBodyPalace": false, "isOriginalPalace": false,
  "heavenlyStem": "壬", "heavenlyStemKey": "renHeavenly",
  "earthlyBranch": "午", "earthlyBranchKey": "wuEarthly",
  "majorStars": [
    { "key": "ziweiMaj", "name": "紫微", "type": "major", "scope": "origin",
      "brightness": "庙", "brightnessKey": "miao", "mutagen": "" }
  ],
  "minorStars": [
    { "key": "wenquMin", "name": "文曲", "type": "soft", "scope": "origin",
      "brightness": "陷", "brightnessKey": "xian", "mutagen": "" }
  ],
  "adjectiveStars": [
    { "key": "fengge", "name": "凤阁", "type": "adjective", "scope": "origin" },
    { "key": "tianfu", "name": "天福", "type": "adjective", "scope": "origin" },
    { "key": "jielu",  "name": "截路", "type": "adjective", "scope": "origin" },
    { "key": "feilian", "name": "蜚廉", "type": "adjective", "scope": "origin" },
    { "key": "nianjie", "name": "年解", "type": "helper", "scope": "origin" }
  ],
  "changsheng12": "衰",   "changsheng12Key": "shuai",
  "boshi12": "青龙",      "boshi12Key": "qinglong",
  "jiangqian12": "灾煞",  "jiangqian12Key": "zhaisha",
  "suiqian12": "丧门",    "suiqian12Key": "sangmen",
  "mutagenStarKeys": ["tianliangMaj", "ziweiMaj", "zuofuMin", "wuquMaj"],
  "decadal": {
    "range": [3, 12],
    "heavenlyStem": "壬", "heavenlyStemKey": "renHeavenly",
    "earthlyBranch": "午", "earthlyBranchKey": "wuEarthly"
  },
  "ages": [5, 17, 29, 41, 53, 65, 77, 89, 101, 113]
}
```

紫微与文曲都有 `mutagen: ""` —— 它们是四化候选星，这一盘上没被化到，
所以键在但值为空，`mutagenKey` 则整个缺省。五颗杂耀连 `brightness` 键都没有。

## `*Key` 字段是什么 [#key-字段是什么]

每个会被翻译的字段旁边都有一个同名加 `Key` 后缀的伴生字段，
取值是 iztro 的 i18n 键名，与盘面语言无关：

```json
{ "name": "紫微", "key": "ziweiMaj", "brightness": "庙", "brightnessKey": "miao" }
```

翻译字段给人看，标识字段给代码用。契约就两条：

1. **凡有译文的属性 `x`，必有配套的 `xKey`**；数组形式的用复数 `Keys`
   （`palaceNameKeys`、`yearlyKeys`）。
2. **实体自身的标识直接叫 `key`**——星耀的标识字段是 `key` 而非 `nameKey`。

唯一的命名分叉在四化：单数 `mutagenKey` 是四化类型（`sihuaLu` 等），
复数 `mutagenStarKeys` 是被化的四颗星的星耀标识。
这份契约由 `semantic_contract` 测试强制——DTO 每个翻译字段都必须有对应的标识字段。

<Callout>
  `*Key` / `key` 系列、`genderKey`、`timeIndex`、`fixLeap`、`language`、`config`
  是 x-iztro 相对 JS iztro 的扩展；其余字段与 iztro 的 `JSON.stringify`
  输出逐键逐值一致，由绑定契约测试守着。判断逻辑请用标识字段，见
  [key 契约](/zh/docs/guide/guides/keys)。
</Callout>

## 导出 JSON [#导出-json]

Python 侧有现成的导出方法，输出即上面这份契约：

```python
chart.to_dict()          # dict
chart.to_json(indent=2)  # str
```

<Callout type="warn" title="不要用 dataclasses.asdict">
  `Astrolabe`、`Palace`、`Star` 之间有回指引用（宫位持有所属星盘），
  `asdict()` 会递归进去直到 `RecursionError`。要 JSON 就用 `to_json()`。
</Callout>
