RaisFastRaisFast
Content Types

完整实战 — 在线课程平台

用内容类型构建一个完整的多表在线课程平台,包含讲师、课程和课时。

本实战构建一个真实的多表系统:在线课程平台,包含三个关联的内容类型 — 讲师、课程和课时。

数据模型

Instructor(讲师)──< Course(课程)>── Tag(标签)

                         └──< Lesson(课时)
  • 一个讲师有很多课程(one_to_many
  • 一门课程属于一个讲师(many_to_one
  • 一门课程有很多课时(one_to_many
  • 一门课程通过中间表关联多个标签(many_to_many
  • 一个课时属于一门课程(many_to_one

1. 讲师

创建 extensions/content_types/instructor.toml

[content_type]
name = "Instructor"
singular = "instructor"
plural = "instructors"
table = "instructors"

[[fields]]
name = "name"
field_type = "text"
required = true

[[fields]]
name = "bio"
field_type = "richtext"

[[fields]]
name = "avatar"
field_type = "media"
media_config = { accept = ["image/*"], max_count = 1 }

[[fields]]
name = "email"
field_type = "email"
required = true
unique = true

[[fields]]
name = "website"
field_type = "text"

[[fields]]
name = "courses"
field_type = "relation"
relation = { relation_type = "one_to_many", target = "courses" }

[content_type.implements]
protocols = ["timestampable"]

2. 课程

创建 extensions/content_types/course.toml

[content_type]
name = "Course"
singular = "course"
plural = "courses"
table = "courses"

[[fields]]
name = "title"
field_type = "text"
required = true
max_length = 200

[[fields]]
name = "slug"
field_type = "uid"
target_field = "title"

[[fields]]
name = "cover"
field_type = "media"
media_config = { accept = ["image/*"], max_count = 1 }

[[fields]]
name = "description"
field_type = "text"
max_length = 500

[[fields]]
name = "price"
field_type = "decimal"
min = 0

[[fields]]
name = "level"
field_type = "enum"
enum_values = ["beginner", "intermediate", "advanced"]
default = "beginner"

[[fields]]
name = "instructor"
field_type = "relation"
relation = { relation_type = "many_to_one", target = "instructors" }

[[fields]]
name = "lessons"
field_type = "relation"
relation = { relation_type = "one_to_many", target = "lessons" }

[[fields]]
name = "tags"
field_type = "relation"
relation = { relation_type = "many_to_many", target = "tags", through = "courses_tags" }

[[fields]]
name = "status"
field_type = "enum"
enum_values = ["draft", "published", "archived"]
default = "draft"

[[indexes]]
fields = ["slug"]
unique = true

[content_type.implements]
protocols = ["timestampable", "ownable", "sortable"]

[[content_type.implements.protocols]]
name = "statusable"
values = "draft,published,archived"
default = "draft"

[content_type.api.list]
access = "public"
filter = 'status = "published"'
fields = ["title", "slug", "cover", "price", "level", "instructor"]

[content_type.api.create]
access = "admin"

[content_type.api.update]
access = "admin"

[content_type.api.delete]
access = "admin"

3. 课时

创建 extensions/content_types/lesson.toml

[content_type]
name = "Lesson"
singular = "lesson"
plural = "lessons"
table = "lessons"

[[fields]]
name = "title"
field_type = "text"
required = true

[[fields]]
name = "content"
field_type = "richtext"

[[fields]]
name = "video_url"
field_type = "text"

[[fields]]
name = "duration_minutes"
field_type = "integer"
min = 1

[[fields]]
name = "is_free"
field_type = "boolean"
default = false

[[fields]]
name = "course"
field_type = "relation"
relation = { relation_type = "many_to_one", target = "courses" }

[content_type.implements]
protocols = ["timestampable", "sortable", "nestable"]

4. 标签(可选)

创建 extensions/content_types/tag.toml

[content_type]
name = "Tag"
singular = "tag"
plural = "tags"
table = "course_tags"

[[fields]]
name = "name"
field_type = "text"
required = true
unique = true

[content_type.implements]
protocols = ["timestampable"]

结果

启动服务器。三张表自动创建,完整的 CRUD API 和跨表关联解析就绪。

列出课程(填充讲师和标签)

curl http://localhost:9898/api/v1/cms/courses?include=instructor,tags
{
  "items": [
    {
      "id": "abc123",
      "title": "Rust 入门到实战",
      "slug": "rust-ru-men-dao-shi-zhan",
      "price": "29.99",
      "level": "beginner",
      "status": "published",
      "instructor": {
        "id": "inst1",
        "name": "Alice Chen",
        "email": "alice@example.com"
      },
      "tags": [
        { "id": "t1", "name": "Rust" },
        { "id": "t2", "name": "系统编程" }
      ]
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 20
}

获取课程详情(填充课时和讲师)

curl http://localhost:9898/api/v1/cms/courses/abc123?include=lessons,instructor

按课程过滤课时

curl "http://localhost:9898/api/v1/cms/lessons?course_id=abc123&sort=sort_key:asc"

创建课程(仅管理员)

curl -X POST http://localhost:9898/api/v1/cms/courses \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Rust 入门到实战",
    "price": 29.99,
    "level": "beginner",
    "instructor": "inst1",
    "tags": ["t1", "t2"],
    "status": "published"
  }'

创建课时

curl -X POST http://localhost:9898/api/v1/cms/lessons \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Hello World",
    "content": "<p>你的第一个 Rust 程序</p>",
    "duration_minutes": 15,
    "is_free": true,
    "course": "abc123"
  }'

更新课时

curl -X PUT http://localhost:9898/api/v1/cms/lessons/{id} \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"duration_minutes": 20}'

搜索课程

curl "http://localhost:9898/api/v1/cms/courses?search=rust&include=instructor"

你获得了什么

功能来源
3 张数据库表TOML 自动迁移
15+ REST 端点自动生成路由
Slug 自动生成uid 字段类型
所有记录自动时间戳timestampable 协议
作者追踪ownable 协议
默认排序sortable 协议
课时树形结构nestable 协议
公开仅显示已发布statusable + 规则引擎
仅管理员可写入访问控制
跨表填充include 参数
标签中间表many_to_many 自动创建
Slug 唯一约束索引定义

零行 Rust 代码,零条手写 SQL。

On this page