Files
twenty/packages/twenty-docs/l/zh/developers/extend/apps/data/system-fields.mdx
T
github-actions[bot] 8707ebb7ac i18n - docs translations (#23515)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-07-29 17:23:57 +02:00

203 lines
9.8 KiB
Plaintext
Raw 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.
---
title: 定位系统元数据
description: 解析 Twenty 在每个对象上自动预配置的元数据的确定性通用标识符,这样你的应用无需硬编码就能引用它。
icon: gears
---
Twenty 中的每个对象都带有你无需自行声明的**系统元数据**,例如一组字段以及带有列的主列表视图。 当对象被预配置时,服务器会创建所有这些内容,并且随着 Twenty 的发展,这个集合也会随之增长。
由于你不会声明它,因此也就没有可供你导入的 `universalIdentifier` 常量。 相反,服务器会以确定性方式**派生**每个标识符,而 `twenty-sdk` 暴露了相同的派生逻辑,这样你的 manifest 就能解析出服务器实际使用的精确值。
## 系统字段
存在于每个对象上的标量字段,你不会使用 [`defineField()`](/l/zh/developers/extend/apps/data/extending-objects) 来声明其中任何一个:
`id`, `createdAt`, `updatedAt`, `deletedAt`, `createdBy`, `updatedBy`, `position`, `searchVector`
那么,如何在[视图](/l/zh/developers/extend/apps/layout/views)中将 `createdAt` 作为一列来引用呢?
### 问题
从 Twenty 2.19 起,系统字段的通用标识符由服务器根据三个输入**确定性派生**:应用通用标识符、对象通用标识符以及字段名称。 自行构造一个 id 并将其硬编码是行不通的:它在服务器上不会匹配任何内容,同步时会拒绝这个悬空引用:
```
Dev sync failed: viewField: INVALID_VIEW_DATA: Field metadata not found
```
### 解决方案
<Note>
`getFieldUniversalIdentifier` 从 `twenty-sdk` 2.21 版本开始可用。
</Note>
使用 `getFieldUniversalIdentifier` 来解析与服务器使用的值完全相同的字段标识符。 它接收这三个输入,并返回字段的通用标识符:
```ts
import { getFieldUniversalIdentifier } from 'twenty-sdk/define';
const createdAtFieldId = getFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
name: 'createdAt',
});
```
* `applicationUniversalIdentifier` 是你的应用标识符,也就是你传递给 [`defineApplication()`](/l/zh/developers/extend/apps/config/application) 的那个。
* `objectUniversalIdentifier` 是该字段所属对象的标识符。
* `name` 是系统字段名称,为上面列出的值之一。
### 示例:视图中的 createdAt 列
典型场景是:为你某个自定义对象的视图添加一列 `createdAt`。 解析字段 id,并像引用其他 `fieldMetadataUniversalIdentifier` 一样引用它:
```ts src/views/example-view.ts
import {
defineView,
getFieldUniversalIdentifier,
} from 'twenty-sdk/define';
const APPLICATION_UNIVERSAL_IDENTIFIER =
'0b04e15c-27b2-4741-9046-b32e07469072';
const MY_OBJECT_UNIVERSAL_IDENTIFIER =
'c782b61c-70fd-4c88-9cd6-4e61ab8d7591';
export default defineView({
universalIdentifier: '70f10d44-144a-4da8-8c6f-3ec2422138c0',
name: 'All records',
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
icon: 'IconList',
position: 0,
fields: [
{
universalIdentifier: '75a90bc4-d901-4df4-85e0-af29db5e0104',
fieldMetadataUniversalIdentifier: getFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
name: 'createdAt',
}),
position: 0,
isVisible: true,
size: 200,
},
],
});
```
同一个解析得到的 id 可在任何需要 `fieldMetadataUniversalIdentifier` 的地方使用:视图字段、筛选器、排序、分组以及页面布局挂件。
<Note>
解析 id,而不是将其硬编码。 由于服务器是根据应用 id、对象 id 和字段名来派生该值的,调用
`getFieldUniversalIdentifier` 能在这些输入发生变化时仍保持引用正确,并在派生逻辑演进时避免偏差。
</Note>
### 系统关系字段
<Note>
`getSystemRelationFieldUniversalIdentifier` 可在 `twenty-sdk`
2.23 及更高版本中使用,并且需要 Twenty 服务器版本为 2.23 或更高。
</Note>
除了上面的标量系统字段之外,服务器还会在每个对象上预置四个**系统关系字段**`timelineActivities`、`attachments`、`noteTargets` 和 `taskTargets`,它们各自指向相应的标准关系对象。
这些字段不会通过 `getFieldUniversalIdentifier` 解析:其标识符不依赖名称,而是由承载该字段的对象和该字段指向的对象推导而来。 通过这种方式,重命名对象永远不会改变其关系字段的标识符。
使用 `getSystemRelationFieldUniversalIdentifier` 来解析它们:
```ts
import {
getSystemRelationFieldUniversalIdentifier,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
// rocket.attachments — the relation field hosted on your custom object
const rocketAttachmentsFieldId = getSystemRelationFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
relationTargetObjectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment.universalIdentifier,
});
```
* `objectUniversalIdentifier` 是**承载**该字段的对象。
* `relationTargetObjectUniversalIdentifier` 是该字段**指向**的对象。
方向由参数的顺序编码。 要解析反向端(例如 `attachment.targetRocket`,即服务器在标准关系对象上创建的 morph 字段),交换这两个参数:
```ts
// attachment.targetRocket — the reverse morph field on Attachment
const attachmentTargetRocketFieldId =
getSystemRelationFieldUniversalIdentifier({
applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment.universalIdentifier,
relationTargetObjectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
});
```
与标量系统字段一样,解析得到的 id 可在任何需要 `fieldMetadataUniversalIdentifier` 的地方使用。
## 系统视图
<Note>
`getSystemViewUniversalIdentifier` 和 `getSystemViewFieldUniversalIdentifier` 可在 `twenty-sdk` 2.26 及更高版本中使用,并且需要 Twenty 服务器版本为 2.26 或更高。
</Note>
服务器还会在每个对象上预配置一个**系统视图**:主列表视图(`All {objectLabelPlural}`,以 `ViewKey.INDEX` 作为键),其中每个可显示字段对应一列。 与系统关联字段类似,它们的标识符是以**与名称无关**的方式派生的,因此重命名对象或字段都不会改变这些标识符。
使用 `getSystemViewUniversalIdentifier` 来解析该视图:
```ts
import { getSystemViewUniversalIdentifier, ViewKey } from 'twenty-sdk/define';
const rocketIndexViewId = getSystemViewUniversalIdentifier({
objectMetadataApplicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
objectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
viewKey: ViewKey.INDEX,
});
```
* `objectMetadataApplicationUniversalIdentifier` 是拥有该**对象**的应用程序,也是视图命名空间所基于的应用。
* `objectUniversalIdentifier` 是该视图所列出的对象。
* `viewKey` 是系统视图键,目前为 `ViewKey.INDEX`。
解析得到的 id 可用于任何需要 `viewUniversalIdentifier` 的地方,例如侧边栏中的 [`NavigationMenuItemType.VIEW`](/l/zh/developers/extend/apps/layout/navigation-menu-items) 条目。 如果只是要打开某个对象的主列表,优先使用带有 `targetObjectUniversalIdentifier` 的 `NavigationMenuItemType.OBJECT`:它不需要派生。
`getSystemViewFieldUniversalIdentifier` 会从视图以及其显示的字段中解析系统视图上的单个**列**:
```ts
import { getSystemViewFieldUniversalIdentifier } from 'twenty-sdk/define';
const rocketNameColumnId = getSystemViewFieldUniversalIdentifier({
fieldMetadataApplicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: rocketIndexViewId,
fieldMetadataUniversalIdentifier: ROCKET_NAME_FIELD_UNIVERSAL_IDENTIFIER,
});
```
注意第一个参数:列是由**其显示的字段**所属的应用程序进行命名空间划分的,而不是由拥有该视图的应用程序进行划分。 你的应用向标准对象添加的字段,会在 Twenty 拥有的视图上,以你的应用为命名空间来派生其列。
<Warning>
系统视图及其列是由**服务器所有**的:解析它们的标识符是为了引用它们,而不是为了声明它们。 [`defineView()`](/l/zh/developers/extend/apps/layout/views) 上的 `key` 已被弃用且会被忽略,因此 manifest 视图永远无法占用 `INDEX` 键,并且服务器已经为你添加的每个字段预配置了一列,所以在系统视图上为同一个字段声明你自己的 `defineViewField()` 会与其发生冲突。
</Warning>
## 标准 Twenty 对象
对于**标准** Twenty 对象(Person、Company、Opportunity 等),你不需要进行任何派生:字段和视图的标识符都是预先计算好的常量,你可以直接导入。
```ts
import { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.createdAt.universalIdentifier
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.updatedAt.universalIdentifier
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.views.allPeople.universalIdentifier
```
当对象是由**你的应用**使用 [`defineObject()`](/l/zh/developers/extend/apps/data/objects) 定义、且不存在此类常量时,再使用上面的辅助方法。
<Note>
`name` 是一个**默认**字段,而不是系统字段。 它保留自己的硬编码
通用标识符,而不是通过
`getFieldUniversalIdentifier` 解析。 在你定义的对象上,请使用你在 `defineObject()` 中赋予它的标识符来引用
`name` 字段。
</Note>