模块
¥Models
由于 Strapi 是一个无头内容管理系统 (CMS),因此为内容创建数据结构是使用该软件最重要的方面之一。模型定义数据结构的表示。
¥As Strapi is a headless Content Management System (CMS), creating a data structure for the content is one of the most important aspects of using the software. Models define a representation of the data structure.
Strapi 有 2 种不同类型的模型:
¥There are 2 different types of models in Strapi:
-
内容类型,可以是集合类型或单一类型,具体取决于它们管理的条目数量,
¥content-types, which can be collection types or single types, depending on how many entries they manage,
-
以及可在多种内容类型中重用的数据结构的组件。
¥and components that are data structures re-usable in multiple content-types.
如果你刚刚开始,直接在管理面板中使用 内容类型生成器 生成一些模型会很方便。用户界面接管了许多验证任务,并展示了可用于创建内容数据结构的所有选项。然后可以使用此文档在代码级别查看生成的模型映射。
¥If you are just starting out, it is convenient to generate some models with the Content-type Builder directly in the admin panel. The user interface takes over a lot of validation tasks and showcases all the options available to create the content's data structure. The generated model mappings can then be reviewed at the code level using this documentation.
模型创建
¥Model creation
内容类型和组件模型的创建和存储方式不同。
¥Content-types and components models are created and stored differently.
内容类型
¥Content-types
可以在 Strapi 中创建内容类型:
¥Content-types in Strapi can be created:
-
与 管理面板中的内容类型生成器 一起,
¥with the Content-type Builder in the admin panel,
-
或使用 Strapi 的交互式 CLI
strapi generate
命令。¥or with Strapi's interactive CLI
strapi generate
command.
内容类型使用以下文件:
¥The content-types use the following files:
-
schema.json
表示模型的 schema 定义。(使用任一方法创建内容类型时自动生成)¥
schema.json
for the model's schema definition. (generated automatically, when creating content-type with either method) -
lifecycles.js
为 生命周期钩子。该文件必须手动创建。¥
lifecycles.js
for lifecycle hooks. This file must be created manually.
这些模型文件存储在 ./src/api/[api-name]/content-types/[content-type-name]/
中,在这些文件夹中找到的任何 JavaScript 或 JSON 文件都将作为内容类型的模型加载(请参阅 项目结构)。
¥These models files are stored in ./src/api/[api-name]/content-types/[content-type-name]/
, and any JavaScript or JSON file found in these folders will be loaded as a content-type's model (see project structure).
在启用 TypeScript 的项目中,可以使用 ts:generate-types
命令生成模式类型。
¥In TypeScript-enabled projects, schema typings can be generated using the ts:generate-types
command.
组件
¥Components
无法使用 CLI 工具创建组件模型。使用 内容类型生成器 或手动创建它们。
¥Component models can't be created with CLI tools. Use the Content-type Builder or create them manually.
组件模型存储在 ./src/components
文件夹中。每个组件都必须位于一个子文件夹中,该子文件夹以该组件所属的类别命名(参见 项目结构)。
¥Components models are stored in the ./src/components
folder. Every component has to be inside a subfolder, named after the category the component belongs to (see project structure).
模型架构
¥Model schema
模型的 schema.json
文件包含:
¥The schema.json
file of a model consists of:
-
settings,例如模型表示的内容类型类型或应存储数据的表名称,
¥settings, such as the kind of content-type the model represents or the table name in which the data should be stored,
-
information,主要用于在管理面板中显示模型并通过 REST 和 GraphQL API 访问它,
¥information, mostly used to display the model in the admin panel and access it through the REST and GraphQL APIs,
-
attributes,描述模型的数据结构,
¥attributes, which describe the data structure of the model,
-
options 用于定义模型上的特定行为。
¥and options used to defined specific behaviors on the model.
模型设置
¥Model settings
模型的常规设置可以使用以下参数进行配置:
¥General settings for the model can be configured with the following parameters:
范围 | 类型 | 描述 |
---|---|---|
collectionName | 字符串 | 应存储数据的数据库表名称 |
kind 可选, 仅适用于内容类型 | 字符串 | 定义内容类型是否为:
|
// ./src/api/[api-name]/content-types/restaurant/schema.json
{
"kind": "collectionType",
"collectionName": "Restaurants_v1",
}
型号信息
¥Model information
模型架构中的 info
键描述了用于在管理面板中显示模型并通过 Content API 访问模型的信息。它包括以下参数:
¥The info
key in the model's schema describes information used to display the model in the admin panel and access it through the Content API. It includes the following parameters:
范围 | 类型 | 描述 |
---|---|---|
displayName | 字符串 | 在管理面板中使用的默认名称 |
singularName | 字符串 | 内容类型名称的单数形式。 用于生成 API 路由和数据库/表集合。 应该是短横线大小写。 |
pluralName | 字符串 | 内容类型名称的复数形式。 用于生成 API 路由和数据库/表集合。 应该是短横线大小写。 |
description | 字符串 | 型号说明 |
"info": {
"displayName": "Restaurant",
"singularName": "restaurant",
"pluralName": "restaurants",
"description": ""
},
模型属性
¥Model attributes
模型的数据结构由属性列表组成。每个属性都有一个 type
参数,该参数描述其性质并将属性定义为简单的数据片段或 Strapi 使用的更复杂的结构。
¥The data structure of a model consists of a list of attributes. Each attribute has a type
parameter, which describes its nature and defines the attribute as a simple piece of data or a more complex structure used by Strapi.
有多种类型的属性可用:
¥Many types of attributes are available:
-
标量类型(例如字符串、日期、数字、布尔值等),
¥scalar types (e.g. strings, dates, numbers, booleans, etc.),
-
Strapi 特定类型,例如:
¥Strapi-specific types, such as:
-
media
表示通过 媒体库 上传的文件¥
media
for files uploaded through the Media library -
relation
描述内容类型之间的 relation¥
relation
to describe a relation between content-types -
customField
描述 自定义字段 及其具体按键¥
customField
to describe custom fields and their specific keys -
component
定义 component(即可用于多种内容类型的数据结构)¥
component
to define a component (i.e. a data structure usable in multiple content-types) -
dynamiczone
定义 动态区(即基于组件列表的灵活空间)¥
dynamiczone
to define a dynamic zone (i.e. a flexible space based on a list of components) -
以及
locale
和localizations
类型,仅由 国际化 (i18n) 插件 使用¥and the
locale
andlocalizations
types, only used by the Internationalization (i18n) plugin
-
属性的 type
参数应为以下值之一:
¥The type
parameter of an attribute should be one of the following values:
类型类别 | 可用类型 |
---|---|
字符串类型 | |
日期类型 | |
号码类型 | |
其他通用类型 | |
Strapi 独有的特殊类型 | |
国际化 (i18n) 相关类型 仅当在内容类型上启用 国际化 时才可使用 |
验证
¥Validations
可以使用以下参数将基本验证应用于属性:
¥Basic validations can be applied to attributes using the following parameters:
范围 | 类型 | 描述 | 默认 |
---|---|---|---|
required | 布尔值 | 如果是 true ,则为此属性添加必需的验证器 | false |
max | 整数 | 检查该值是否大于或等于给定的最大值 | * |
min | 整数 | 检查该值是否小于或等于给定的最小值 | * |
minLength | 整数 | 字段输入值的最小字符数 | * |
maxLength | 整数 | 字段输入值的最大字符数 | * |
private | 布尔值 | 如果 true ,该属性将从服务器响应中删除。💡这对于隐藏敏感数据很有用。 | false |
configurable | 布尔值 | 如果是 false ,则无法通过 Content-type Builder 插件配置该属性。 | true |
{
// ...
"attributes": {
"title": {
"type": "string",
"minLength": 3,
"maxLength": 99,
"unique": true
},
"description": {
"default": "My description",
"type": "text",
"required": true
},
"slug": {
"type": "uid",
"targetField": "title"
}
// ...
}
}
数据库验证和设置
¥Database validations and settings
这些设置应保留给高级用途,因为它们可能会破坏某些功能。没有计划使这些设置稳定。
¥These settings should be reserved to an advanced usage, as they might break some features. There are no plans to make these settings stable.
数据库验证和设置是在架构迁移期间直接传递到 tableBuilder
Knex.js 函数的自定义选项。数据库验证允许对自定义列设置进行高级控制。以下选项在每个属性的 column: {}
对象中设置:
¥Database validations and settings are custom options passed directly onto the tableBuilder
Knex.js function during schema migrations. Database validations allow for an advanced degree of control for setting custom column settings. The following options are set in a column: {}
object per attribute:
范围 | 类型 | 描述 | 默认 |
---|---|---|---|
name | string | 更改数据库中列的名称 | * |
defaultTo | string | 设置数据库 defaultTo ,通常与 notNullable 一起使用 | * |
notNullable | 布尔值 | 设置数据库 notNullable ,确保列不能为空 | false |
unsigned | 布尔值 | 仅适用于数字列,消除了负数的能力,但最大长度加倍 | false |
unique | 布尔值 | 强制数据库级别唯一,使用草稿和发布功能时请小心 | false |
type | string | 更改数据库类型,如果 type 有参数,则应将它们传递到 args | * |
args | array | 传递到 Knex.js 函数的参数会更改 type 等内容 | [] |
{
// ...
"attributes": {
"title": {
"type": "string",
"minLength": 3,
"maxLength": 99,
"unique": true,
"column": {
"unique": true // enforce database unique also
}
},
"description": {
"default": "My description",
"type": "text",
"required": true,
"column": {
"defaultTo": "My description", // set database level default
"notNullable": true // enforce required at database level, even for drafts
}
},
"rating": {
"type": "decimal",
"default": 0,
"column": {
"defaultTo": 0,
"type": "decimal", // using the native decimal type but allowing for custom precision
"args": [
6,1 // using custom precision and scale
]
}
}
// ...
}
}
uid
型
¥uid
type
uid
类型用于根据 2 个可选参数,使用唯一标识符 (UID)(例如文章的别名)自动预填充管理面板中的字段值:
¥The uid
type is used to automatically prefill the field value in the admin panel with a unique identifier (UID) (e.g. slugs for articles) based on 2 optional parameters:
-
targetField
(字符串):如果使用,定义为目标的字段值将用于自动生成 UID。¥
targetField
(string): If used, the value of the field defined as a target is used to auto-generate the UID. -
options
(字符串):如果使用,则 UID 是根据传递给 底层uid
生成器 的一组选项生成的。生成的uid
必须匹配以下正则表达式模式:/^[A-Za-z0-9-_.~]*$
。¥
options
(string): If used, the UID is generated based on a set of options passed to the underlyinguid
generator. The resultinguid
must match the following regular expression pattern:/^[A-Za-z0-9-_.~]*$
.
关系
¥Relations
关系将内容类型链接在一起。关系在模型的 attributes 和 type: 'relation'
中明确定义,并接受以下附加参数:
¥Relations link content-types together. Relations are explicitly defined in the attributes of a model with type: 'relation'
and accept the following additional parameters:
范围 | 描述 |
---|---|
relation | 这些值之间的关系类型:
|
target | 接受字符串值作为目标内容类型的名称 |
mappedBy 和 inversedBy 可选 | 在双向关系中,拥有方声明 inversedBy 密钥,而反向方声明 mappedBy 密钥 |
- One-to-one
- One-to-Many
- Many-to-One
- Many-to-Many
当一个条目只能链接到另一个条目时,一对一关系非常有用。
¥One-to-One relationships are useful when one entry can be linked to only one other entry.
它们可以是单向的或双向的。在单向关系中,只能查询其中一个模型及其链接项。
¥They can be unidirectional or bidirectional. In unidirectional relationships, only one of the models can be queried with its linked item.
Unidirectional use case example:
-
博客文章属于一个类别。
¥A blog article belongs to a category.
-
查询一篇文章可以检索它的类别,
¥Querying an article can retrieve its category,
-
但查询类别不会检索拥有的文章。
¥but querying a category won't retrieve the owned article.
// …
attributes: {
category: {
type: 'relation',
relation: 'oneToOne',
target: 'category',
},
},
// …
Bidirectional use case example:
-
博客文章属于一个类别。
¥A blog article belongs to a category.
-
查询一篇文章可以检索它的类别,
¥Querying an article can retrieve its category,
-
查询类别也会检索其拥有的文章。
¥and querying a category also retrieves its owned article.
// …
attributes: {
category: {
type: 'relation',
relation: 'oneToOne',
target: 'category',
inversedBy: 'article',
},
},
// …
// …
attributes: {
article: {
type: 'relation',
relation: 'oneToOne',
target: 'article',
mappedBy: 'category',
},
},
// …
一对多关系在以下情况下很有用:
¥One-to-Many relationships are useful when:
-
内容类型 A 的条目链接到另一个内容类型 B 的许多条目,
¥an entry from a content-type A is linked to many entries of another content-type B,
-
而内容类型 B 的条目仅链接到内容类型 A 的一个条目。
¥while an entry from content-type B is linked to only one entry of content-type A.
一对多关系始终是双向的,通常用相应的多对一关系定义:
¥One-to-many relationships are always bidirectional, and are usually defined with the corresponding Many-to-One relationship:
Example:
一个人可以拥有很多植物,但一株植物只能属于一个人。
¥A person can own many plants, but a plant is owned by only one person.
// …
attributes: {
owner: {
type: 'relation',
relation: 'manyToOne',
target: 'api::person.person',
inversedBy: 'plants',
},
},
// …
// …
attributes: {
plants: {
type: 'relation',
relation: 'oneToMany',
target: 'api::plant.plant',
mappedBy: 'owner',
},
},
// …
多对一关系对于将多个条目链接到一个条目非常有用。
¥Many-to-One relationships are useful to link many entries to one entry.
它们可以是单向的或双向的。在单向关系中,只能查询其中一个模型及其链接项。
¥They can be unidirectional or bidirectional. In unidirectional relationships, only one of the models can be queried with its linked item.
Unidirectional use case example:
一本书可以由许多作者撰写。
¥A book can be written by many authors.
// …
attributes: {
author: {
type: 'relation',
relation: 'manyToOne',
target: 'author',
},
},
// …
Bidirectional use case example:
一篇文章只属于一个类别,但一个类别可以包含许多文章。
¥An article belongs to only one category but a category has many articles.
// …
attributes: {
author: {
type: 'relation',
relation: 'manyToOne',
target: 'category',
inversedBy: 'article',
},
},
// …
// …
attributes: {
books: {
type: 'relation',
relation: 'oneToMany',
target: 'article',
mappedBy: 'category',
},
},
// …
多对多关系在以下情况下很有用:
¥Many-to-Many relationships are useful when:
-
内容类型 A 的条目链接到内容类型 B 的许多条目,
¥an entry from content-type A is linked to many entries of content-type B,
-
内容类型 B 中的条目也链接到内容类型 A 中的许多条目。
¥and an entry from content-type B is also linked to many entries from content-type A.
多对多关系可以是单向的,也可以是双向的。在单向关系中,只能查询其中一个模型及其链接项。
¥Many-to-many relationships can be unidirectional or bidirectional. In unidirectional relationships, only one of the models can be queried with its linked item.
Unidirectional use case example:
// …
attributes: {
categories: {
type: 'relation',
relation: 'manyToMany',
target: 'category',
},
},
// …
Bidirectional use case example:
一篇文章可以有多个标签,一个标签可以分配给多篇文章。
¥An article can have many tags and a tag can be assigned to many articles.
// …
attributes: {
tags: {
type: 'relation',
relation: 'manyToMany',
target: 'tag',
inversedBy: 'articles',
},
},
// …
// …
attributes: {
articles: {
type: 'relation',
relation: 'manyToMany',
target: 'article',
mappedBy: 'tag',
},
},
// …
自定义字段
¥Custom fields
自定义字段 通过向内容类型添加新类型的字段来扩展 Strapi 的功能。自定义字段在带有 type: customField
的模型的 attributes 中显式定义。自定义字段的属性还接受:
¥Custom fields extend Strapi’s capabilities by adding new types of fields to content-types. Custom fields are explicitly defined in the attributes of a model with type: customField
.
Custom fields' attributes also accept:
自定义字段的属性还显示以下特性:
¥Custom fields' attributes also show the following specificities:
-
customField
属性,其值充当唯一标识符,指示应使用哪个已注册的自定义字段。其值如下:¥a
customField
attribute whose value acts as a unique identifier to indicate which registered custom field should be used. Its value follows:-
如果插件创建了自定义字段,则为
plugin::plugin-name.field-name
格式¥either the
plugin::plugin-name.field-name
format if a plugin created the custom field -
或特定于当前 Strapi 应用的自定义字段的
global::field-name
格式¥or the
global::field-name
format for a custom field specific to the current Strapi application
-
-
以及其他参数,具体取决于注册自定义字段时定义的内容(参见 自定义字段文档)。
¥and additional parameters depending on what has been defined when registering the custom field (see custom fields documentation).
{
// …
"attributes": {
"attributeName": { // attributeName would be replaced by the actual attribute name
"type": "customField",
"customField": "plugin::color-picker.color",
"options": {
"format": "hex"
}
}
}
// …
}
组件
¥Components
组件字段创建内容类型和组件结构之间的关系。组件在具有 type: 'component'
的模型的 attributes 中显式定义,并接受以下附加参数:
¥Component fields create a relation between a content-type and a component structure. Components are explicitly defined in the attributes of a model with type: 'component'
and accept the following additional parameters:
范围 | 类型 | 描述 |
---|---|---|
repeatable | 布尔值 | 可能是 true 或 false ,具体取决于组件是否可重复 |
component | 字符串 | 定义相应的组件,格式如下:<category>.<componentName> |
{
"attributes": {
"openinghours": {
"type": "component",
"repeatable": true,
"component": "restaurant.openinghours"
}
}
}
动态区域
¥Dynamic zones
动态区域创建了一个灵活的空间,可以根据 components 的混合列表在其中编写内容。
¥Dynamic zones create a flexible space in which to compose content, based on a mixed list of components.
动态区域在具有 type: 'dynamiczone'
的模型的 attributes 中明确定义。它们还接受 components
数组,其中每个组件应按照以下格式命名:<category>.<componentName>
。
¥Dynamic zones are explicitly defined in the attributes of a model with type: 'dynamiczone'
. They also accept a components
array, where each component should be named following this format: <category>.<componentName>
.
{
"attributes": {
"body": {
"type": "dynamiczone",
"components": ["article.slider", "article.content"]
}
}
}
型号选择
¥Model options
options
键用于定义特定行为并接受以下参数:
¥The options
key is used to define specific behaviors and accepts the following parameter:
范围 | 类型 | 描述 |
---|---|---|
privateAttributes | 字符串数组 | 允许将一组属性视为私有属性,即使它们实际上并未在模型中定义为属性。它可用于从 API 响应时间戳中删除它们。 模型中定义的 privateAttributes 与全局 Strapi 配置中定义的 privateAttributes 合并。 |
draftAndPublish | 布尔值 | 启用草稿和发布功能。 默认值: true (如果内容类型是从交互式 CLI 创建的,则为 false )。 |
populateCreatorFields | 布尔值 | 利用插件中的 createdBy 和 updatedBy 钩子的插件开发者需要重构其代码。false 。 |
{
"options": {
"privateAttributes": ["id", "createdAt"],
"draftAndPublish": true
}
}
生命周期钩子
¥Lifecycle hooks
生命周期钩子是调用 Strapi 查询时触发的函数。当通过管理面板管理内容或使用 queries
· 开发自定义代码时,它们会自动触发
¥Lifecycle hooks are functions that get triggered when Strapi queries are called. They are triggered automatically when managing content through the administration panel or when developing custom code using queries
·
生命周期钩子可以通过声明或编程方式自定义。
¥Lifecycle hooks can be customized declaratively or programmatically.
直接使用 knex 库而不是 Strapi 函数时,不会触发生命周期钩子。
¥Lifecycles hooks are not triggered when using directly the knex library instead of Strapi functions.
文档服务 API 根据调用的方法触发各种数据库生命周期钩子。有关完整参考,请参阅 文档服务 API:生命周期钩子。批量操作生命周期(createMany
、updateMany
、deleteMany
)永远不会由文档服务 API 方法触发。文档服务中间件 也可以实现。
¥The Document Service API triggers various database lifecycle hooks based on which method is called. For a complete reference, see Document Service API: Lifecycle hooks. Bulk actions lifecycles (createMany
, updateMany
, deleteMany
) will never be triggered by a Document Service API method. Document Service middlewares can be implemented too.
可用的生命周期事件
¥Available lifecycle events
以下生命周期事件可用:
¥The following lifecycle events are available:
-
beforeCreate
-
beforeCreateMany
-
afterCreate
-
afterCreateMany
-
beforeUpdate
-
beforeUpdateMany
-
afterUpdate
-
afterUpdateMany
-
beforeDelete
-
beforeDeleteMany
-
afterDelete
-
afterDeleteMany
-
beforeCount
-
afterCount
-
beforeFindOne
-
afterFindOne
-
beforeFindMany
-
afterFindMany
钩子 event
对象
¥Hook event
object
生命周期钩子是采用 event
参数的函数,该参数是具有以下键的对象:
¥Lifecycle hooks are functions that take an event
parameter, an object with the following keys:
密钥 | 类型 | 描述 |
---|---|---|
action | 字符串 | 已触发的生命周期事件(参见 list) |
model | 字符串数组(uid) | 将监听其事件的内容类型的 uid 数组。 如果未提供此参数,则会监听所有内容类型的事件。 |
params | 目的 | 接受以下参数:
|
result | 目的 | 可选,仅适用于 afterXXX 事件包含操作的结果。 |
state | 目的 | 查询状态,可用于在查询的 beforeXXX 和 afterXXX 事件之间共享状态。 |
声明式和编程式用法
¥Declarative and programmatic usage
要配置内容类型生命周期钩子,请在 ./src/api/[api-name]/content-types/[content-type-name]/
文件夹中创建 lifecycles.js
文件。
¥To configure a content-type lifecycle hook, create a lifecycles.js
file in the ./src/api/[api-name]/content-types/[content-type-name]/
folder.
每个事件监听器都会按顺序调用。它们可以是同步的或异步的。
¥Each event listener is called sequentially. They can be synchronous or asynchronous.
- JavaScript
- TypeScript
module.exports = {
beforeCreate(event) {
const { data, where, select, populate } = event.params;
// let's do a 20% discount everytime
event.params.data.price = event.params.data.price * 0.8;
},
afterCreate(event) {
const { result, params } = event;
// do something to the result;
},
};
export default {
beforeCreate(event) {
const { data, where, select, populate } = event.params;
// let's do a 20% discount everytime
event.params.data.price = event.params.data.price * 0.8;
},
afterCreate(event) {
const { result, params } = event;
// do something to the result;
},
};
使用数据库层 API,还可以注册订阅者并以编程方式监听事件:
¥Using the database layer API, it's also possible to register a subscriber and listen to events programmatically:
module.exports = {
async bootstrap({ strapi }) {
// registering a subscriber
strapi.db.lifecycles.subscribe({
models: [], // optional;
beforeCreate(event) {
const { data, where, select, populate } = event.params;
event.state = 'doStuffAfterWards';
},
afterCreate(event) {
if (event.state === 'doStuffAfterWards') {
}
const { result, params } = event;
// do something to the result
},
});
// generic subscribe for generic handling
strapi.db.lifecycles.subscribe((event) => {
if (event.action === 'beforeCreate') {
// do something
}
});
}
}