notion-api

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Notion API Integration Skill

Notion API集成技能

Master the Notion API for workspace automation, including databases, pages, blocks, query/filter syntax, and integration patterns. This skill covers the official REST API and Python SDK for building powerful Notion integrations.
掌握用于工作区自动化的Notion API,包括数据库、页面、块、查询/过滤语法及集成模式。本技能涵盖官方REST API和Python SDK,用于构建功能强大的Notion集成。

When to Use This Skill

何时使用本技能

USE Notion API when:

适合使用Notion API的场景:

  • Automating database entries and updates
  • Building custom dashboards from Notion data
  • Syncing data between Notion and external systems
  • Creating pages programmatically from templates
  • Querying databases with complex filters
  • Building integrations with other productivity tools
  • Generating reports from Notion databases
  • Implementing workflow automations
  • 自动化数据库条目创建与更新
  • 基于Notion数据构建自定义仪表板
  • 在Notion与外部系统之间同步数据
  • 通过模板程序化创建页面
  • 使用复杂过滤器查询数据库
  • 与其他生产力工具构建集成
  • 从Notion数据库生成报告
  • 实现工作流自动化

DON'T USE Notion API when:

不适合使用Notion API的场景:

  • Need real-time sync (API has rate limits)
  • Building chat/messaging features (use Slack API)
  • Need file storage solution (use dedicated storage)
  • Simple task management only (use Todoist API)
  • Need offline-first solution (use Obsidian)
  • Require sub-second response times
  • 需要实时同步(API存在速率限制)
  • 构建聊天/消息功能(使用Slack API)
  • 需要文件存储解决方案(使用专用存储服务)
  • 仅需简单任务管理(使用Todoist API)
  • 需要离线优先解决方案(使用Obsidian)
  • 要求亚秒级响应时间

Prerequisites

前置条件

Create Integration

创建集成

markdown
1. Go to https://www.notion.so/my-integrations
2. Click "New integration"
3. Name: "My Integration"
4. Select workspace
5. Set capabilities (Read/Write content, etc.)
6. Copy the "Internal Integration Token"
markdown
1. 访问 https://www.notion.so/my-integrations
2. 点击「New integration」
3. 名称:「My Integration」
4. 选择工作区
5. 设置权限(如读取/写入内容等)
6. 复制「Internal Integration Token」

Connect Integration to Pages

将集成连接到页面

markdown
1. Open the Notion page/database you want to access
2. Click "..." menu (top right)
3. Click "Connections" > "Connect to" > Your integration
4. Integration can now access this page and children
markdown
1. 打开要访问的Notion页面/数据库
2. 点击右上角的「...」菜单
3. 点击「Connections」>「Connect to」> 选择你的集成
4. 集成现在可以访问此页面及其子页面

Environment Setup

环境设置

bash
undefined
bash
undefined

Set environment variable

设置环境变量

export NOTION_API_KEY="secret_xxxxxxxxxxxxxxxxxxxxx"
export NOTION_API_KEY="secret_xxxxxxxxxxxxxxxxxxxxx"

Verify connection

验证连接

curl -s "https://api.notion.com/v1/users/me"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28" | jq
undefined
curl -s "https://api.notion.com/v1/users/me"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28" | jq
undefined

Python SDK Installation

Python SDK安装

bash
undefined
bash
undefined

Install official Python client

安装官方Python客户端

pip install notion-client
pip install notion-client

Or with uv

或使用uv

uv pip install notion-client
uv pip install notion-client

Additional dependencies

安装额外依赖

pip install python-dotenv requests
undefined
pip install python-dotenv requests
undefined

Verify Setup

验证设置

python
from notion_client import Client
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])
python
from notion_client import Client
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])

Test connection

测试连接

me = notion.users.me() print(f"Connected as: {me['name']}")
me = notion.users.me() print(f"Connected as: {me['name']}")

List accessible databases

列出可访问的数据库

databases = notion.search(filter={"property": "object", "value": "database"}) print(f"Found {len(databases['results'])} databases")
undefined
databases = notion.search(filter={"property": "object", "value": "database"}) print(f"Found {len(databases['results'])} databases")
undefined

Core Capabilities

核心功能

1. Database Operations

1. 数据库操作

List and Search Databases:
bash
undefined
列出并搜索数据库:
bash
undefined

Search for databases

搜索数据库

curl -s -X POST "https://api.notion.com/v1/search"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{ "filter": { "property": "object", "value": "database" } }' | jq '.results[] | {id: .id, title: .title[0].plain_text}'
curl -s -X POST "https://api.notion.com/v1/search"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{ "filter": { "property": "object", "value": "database" } }' | jq '.results[] | {id: .id, title: .title[0].plain_text}'

Get database schema

获取数据库架构

curl -s "https://api.notion.com/v1/databases/DATABASE_ID"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28" | jq '.properties'

**Python - Database Operations:**
```python
from notion_client import Client
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])
curl -s "https://api.notion.com/v1/databases/DATABASE_ID"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28" | jq '.properties'

**Python - 数据库操作:**
```python
from notion_client import Client
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])

Search for databases

搜索数据库

results = notion.search( filter={"property": "object", "value": "database"} )
for db in results["results"]: title = db["title"][0]["plain_text"] if db["title"] else "Untitled" print(f"Database: {title} (ID: {db['id']})")
results = notion.search( filter={"property": "object", "value": "database"} )
for db in results["results"]: title = db["title"][0]["plain_text"] if db["title"] else "Untitled" print(f"Database: {title} (ID: {db['id']})")

Get database details

获取数据库详情

database = notion.databases.retrieve(database_id="your-database-id") print(f"Properties: {list(database['properties'].keys())}")
database = notion.databases.retrieve(database_id="your-database-id") print(f"Properties: {list(database['properties'].keys())}")

Create database

创建数据库

new_db = notion.databases.create( parent={"type": "page_id", "page_id": "parent-page-id"}, title=[{"type": "text", "text": {"content": "Tasks Database"}}], properties={ "Name": {"title": {}}, "Status": { "select": { "options": [ {"name": "To Do", "color": "gray"}, {"name": "In Progress", "color": "blue"}, {"name": "Done", "color": "green"} ] } }, "Priority": { "select": { "options": [ {"name": "High", "color": "red"}, {"name": "Medium", "color": "yellow"}, {"name": "Low", "color": "gray"} ] } }, "Due Date": {"date": {}}, "Assignee": {"people": {}}, "Tags": {"multi_select": {"options": []}}, "Completed": {"checkbox": {}}, "Notes": {"rich_text": {}} } ) print(f"Created database: {new_db['id']}")
new_db = notion.databases.create( parent={"type": "page_id", "page_id": "parent-page-id"}, title=[{"type": "text", "text": {"content": "Tasks Database"}}], properties={ "Name": {"title": {}}, "Status": { "select": { "options": [ {"name": "To Do", "color": "gray"}, {"name": "In Progress", "color": "blue"}, {"name": "Done", "color": "green"} ] } }, "Priority": { "select": { "options": [ {"name": "High", "color": "red"}, {"name": "Medium", "color": "yellow"}, {"name": "Low", "color": "gray"} ] } }, "Due Date": {"date": {}}, "Assignee": {"people": {}}, "Tags": {"multi_select": {"options": []}}, "Completed": {"checkbox": {}}, "Notes": {"rich_text": {}} } ) print(f"Created database: {new_db['id']}")

Update database

更新数据库

notion.databases.update( database_id="your-database-id", title=[{"type": "text", "text": {"content": "Updated Title"}}], properties={ "New Property": {"rich_text": {}} } )
undefined
notion.databases.update( database_id="your-database-id", title=[{"type": "text", "text": {"content": "Updated Title"}}], properties={ "New Property": {"rich_text": {}} } )
undefined

2. Query Databases

2. 查询数据库

Basic Query:
bash
undefined
基础查询:
bash
undefined

Query all items

查询所有条目

curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{}' | jq '.results'
curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{}' | jq '.results'

Query with filter

带过滤器的查询

curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{ "filter": { "property": "Status", "select": { "equals": "In Progress" } } }' | jq '.results'
curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{ "filter": { "property": "Status", "select": { "equals": "In Progress" } } }' | jq '.results'

Query with sort

带排序的查询

curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{ "sorts": [ { "property": "Due Date", "direction": "ascending" } ] }' | jq '.results'

**Python - Query Operations:**
```python
curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{ "sorts": [ { "property": "Due Date", "direction": "ascending" } ] }' | jq '.results'

**Python - 查询操作:**
```python

Simple query

简单查询

results = notion.databases.query(database_id="your-database-id") for page in results["results"]: props = page["properties"] name = props["Name"]["title"][0]["plain_text"] if props["Name"]["title"] else "Untitled" print(f"- {name}")
results = notion.databases.query(database_id="your-database-id") for page in results["results"]: props = page["properties"] name = props["Name"]["title"][0]["plain_text"] if props["Name"]["title"] else "Untitled" print(f"- {name}")

Query with filter

带过滤器的查询

results = notion.databases.query( database_id="your-database-id", filter={ "property": "Status", "select": { "equals": "In Progress" } } )
results = notion.databases.query( database_id="your-database-id", filter={ "property": "Status", "select": { "equals": "In Progress" } } )

Query with multiple filters (AND)

带多过滤器的查询(AND)

results = notion.databases.query( database_id="your-database-id", filter={ "and": [ { "property": "Status", "select": {"equals": "In Progress"} }, { "property": "Priority", "select": {"equals": "High"} } ] } )
results = notion.databases.query( database_id="your-database-id", filter={ "and": [ { "property": "Status", "select": {"equals": "In Progress"} }, { "property": "Priority", "select": {"equals": "High"} } ] } )

Query with OR filter

带OR过滤器的查询

results = notion.databases.query( database_id="your-database-id", filter={ "or": [ {"property": "Status", "select": {"equals": "To Do"}}, {"property": "Status", "select": {"equals": "In Progress"}} ] } )
results = notion.databases.query( database_id="your-database-id", filter={ "or": [ {"property": "Status", "select": {"equals": "To Do"}}, {"property": "Status", "select": {"equals": "In Progress"}} ] } )

Query with sorting

带排序的查询

results = notion.databases.query( database_id="your-database-id", sorts=[ {"property": "Priority", "direction": "ascending"}, {"property": "Due Date", "direction": "ascending"} ] )
results = notion.databases.query( database_id="your-database-id", sorts=[ {"property": "Priority", "direction": "ascending"}, {"property": "Due Date", "direction": "ascending"} ] )

Paginated query

分页查询

def query_all_pages(database_id, filter=None): """Query all pages with pagination""" all_results = [] has_more = True start_cursor = None
while has_more:
    response = notion.databases.query(
        database_id=database_id,
        filter=filter,
        start_cursor=start_cursor,
        page_size=100
    )
    all_results.extend(response["results"])
    has_more = response["has_more"]
    start_cursor = response.get("next_cursor")

return all_results
all_items = query_all_pages("your-database-id") print(f"Total items: {len(all_items)}")
undefined
def query_all_pages(database_id, filter=None): """分页查询所有页面""" all_results = [] has_more = True start_cursor = None
while has_more:
    response = notion.databases.query(
        database_id=database_id,
        filter=filter,
        start_cursor=start_cursor,
        page_size=100
    )
    all_results.extend(response["results"])
    has_more = response["has_more"]
    start_cursor = response.get("next_cursor")

return all_results
all_items = query_all_pages("your-database-id") print(f"Total items: {len(all_items)}")
undefined

3. Filter Syntax Reference

3. 过滤器语法参考

Text Filters:
python
undefined
文本过滤器:
python
undefined

Text property filters

文本属性过滤器

{"property": "Name", "title": {"equals": "Exact Match"}} {"property": "Name", "title": {"does_not_equal": "Not This"}} {"property": "Name", "title": {"contains": "partial"}} {"property": "Name", "title": {"does_not_contain": "exclude"}} {"property": "Name", "title": {"starts_with": "Prefix"}} {"property": "Name", "title": {"ends_with": "suffix"}} {"property": "Name", "title": {"is_empty": True}} {"property": "Name", "title": {"is_not_empty": True}}
{"property": "Name", "title": {"equals": "Exact Match"}} {"property": "Name", "title": {"does_not_equal": "Not This"}} {"property": "Name", "title": {"contains": "partial"}} {"property": "Name", "title": {"does_not_contain": "exclude"}} {"property": "Name", "title": {"starts_with": "Prefix"}} {"property": "Name", "title": {"ends_with": "suffix"}} {"property": "Name", "title": {"is_empty": True}} {"property": "Name", "title": {"is_not_empty": True}}

Rich text property

富文本属性

{"property": "Notes", "rich_text": {"contains": "keyword"}}

**Number Filters:**
```python
{"property": "Amount", "number": {"equals": 100}}
{"property": "Amount", "number": {"does_not_equal": 0}}
{"property": "Amount", "number": {"greater_than": 50}}
{"property": "Amount", "number": {"less_than": 100}}
{"property": "Amount", "number": {"greater_than_or_equal_to": 10}}
{"property": "Amount", "number": {"less_than_or_equal_to": 99}}
{"property": "Amount", "number": {"is_empty": True}}
{"property": "Amount", "number": {"is_not_empty": True}}
Date Filters:
python
{"property": "Due Date", "date": {"equals": "2025-01-17"}}
{"property": "Due Date", "date": {"before": "2025-01-20"}}
{"property": "Due Date", "date": {"after": "2025-01-10"}}
{"property": "Due Date", "date": {"on_or_before": "2025-01-17"}}
{"property": "Due Date", "date": {"on_or_after": "2025-01-01"}}
{"property": "Due Date", "date": {"is_empty": True}}
{"property": "Due Date", "date": {"is_not_empty": True}}
{"property": "Notes", "rich_text": {"contains": "keyword"}}

**数字过滤器:**
```python
{"property": "Amount", "number": {"equals": 100}}
{"property": "Amount", "number": {"does_not_equal": 0}}
{"property": "Amount", "number": {"greater_than": 50}}
{"property": "Amount", "number": {"less_than": 100}}
{"property": "Amount", "number": {"greater_than_or_equal_to": 10}}
{"property": "Amount", "number": {"less_than_or_equal_to": 99}}
{"property": "Amount", "number": {"is_empty": True}}
{"property": "Amount", "number": {"is_not_empty": True}}
日期过滤器:
python
{"property": "Due Date", "date": {"equals": "2025-01-17"}}
{"property": "Due Date", "date": {"before": "2025-01-20"}}
{"property": "Due Date", "date": {"after": "2025-01-10"}}
{"property": "Due Date", "date": {"on_or_before": "2025-01-17"}}
{"property": "Due Date", "date": {"on_or_after": "2025-01-01"}}
{"property": "Due Date", "date": {"is_empty": True}}
{"property": "Due Date", "date": {"is_not_empty": True}}

Relative date filters

相对日期过滤器

{"property": "Due Date", "date": {"past_week": {}}} {"property": "Due Date", "date": {"past_month": {}}} {"property": "Due Date", "date": {"past_year": {}}} {"property": "Due Date", "date": {"next_week": {}}} {"property": "Due Date", "date": {"next_month": {}}} {"property": "Due Date", "date": {"next_year": {}}} {"property": "Due Date", "date": {"this_week": {}}}

**Select/Multi-Select Filters:**
```python
{"property": "Due Date", "date": {"past_week": {}}} {"property": "Due Date", "date": {"past_month": {}}} {"property": "Due Date", "date": {"past_year": {}}} {"property": "Due Date", "date": {"next_week": {}}} {"property": "Due Date", "date": {"next_month": {}}} {"property": "Due Date", "date": {"next_year": {}}} {"property": "Due Date", "date": {"this_week": {}}}

**单选/多选过滤器:**
```python

Select

单选

{"property": "Status", "select": {"equals": "Done"}} {"property": "Status", "select": {"does_not_equal": "Done"}} {"property": "Status", "select": {"is_empty": True}} {"property": "Status", "select": {"is_not_empty": True}}
{"property": "Status", "select": {"equals": "Done"}} {"property": "Status", "select": {"does_not_equal": "Done"}} {"property": "Status", "select": {"is_empty": True}} {"property": "Status", "select": {"is_not_empty": True}}

Multi-select

多选

{"property": "Tags", "multi_select": {"contains": "urgent"}} {"property": "Tags", "multi_select": {"does_not_contain": "archived"}} {"property": "Tags", "multi_select": {"is_empty": True}} {"property": "Tags", "multi_select": {"is_not_empty": True}}

**Checkbox Filters:**
```python
{"property": "Completed", "checkbox": {"equals": True}}
{"property": "Completed", "checkbox": {"equals": False}}
Relation and Rollup Filters:
python
undefined
{"property": "Tags", "multi_select": {"contains": "urgent"}} {"property": "Tags", "multi_select": {"does_not_contain": "archived"}} {"property": "Tags", "multi_select": {"is_empty": True}} {"property": "Tags", "multi_select": {"is_not_empty": True}}

**复选框过滤器:**
```python
{"property": "Completed", "checkbox": {"equals": True}}
{"property": "Completed", "checkbox": {"equals": False}}
关联与汇总过滤器:
python
undefined

Relation

关联

{"property": "Project", "relation": {"contains": "page-id"}} {"property": "Project", "relation": {"does_not_contain": "page-id"}} {"property": "Project", "relation": {"is_empty": True}} {"property": "Project", "relation": {"is_not_empty": True}}
{"property": "Project", "relation": {"contains": "page-id"}} {"property": "Project", "relation": {"does_not_contain": "page-id"}} {"property": "Project", "relation": {"is_empty": True}} {"property": "Project", "relation": {"is_not_empty": True}}

Rollup (depends on rollup type)

汇总(取决于汇总类型)

{"property": "Total Tasks", "rollup": {"number": {"greater_than": 5}}} {"property": "Completion", "rollup": {"number": {"equals": 100}}}

**Compound Filters:**
```python
{"property": "Total Tasks", "rollup": {"number": {"greater_than": 5}}} {"property": "Completion", "rollup": {"number": {"equals": 100}}}

**复合过滤器:**
```python

AND

AND

{ "and": [ {"property": "Status", "select": {"equals": "In Progress"}}, {"property": "Priority", "select": {"equals": "High"}}, {"property": "Due Date", "date": {"before": "2025-02-01"}} ] }
{ "and": [ {"property": "Status", "select": {"equals": "In Progress"}}, {"property": "Priority", "select": {"equals": "High"}}, {"property": "Due Date", "date": {"before": "2025-02-01"}} ] }

OR

OR

{ "or": [ {"property": "Status", "select": {"equals": "To Do"}}, {"property": "Status", "select": {"equals": "In Progress"}} ] }
{ "or": [ {"property": "Status", "select": {"equals": "To Do"}}, {"property": "Status", "select": {"equals": "In Progress"}} ] }

Nested (AND with OR)

嵌套(AND包含OR)

{ "and": [ { "or": [ {"property": "Priority", "select": {"equals": "High"}}, {"property": "Priority", "select": {"equals": "Medium"}} ] }, {"property": "Status", "select": {"does_not_equal": "Done"}} ] }
undefined
{ "and": [ { "or": [ {"property": "Priority", "select": {"equals": "High"}}, {"property": "Priority", "select": {"equals": "Medium"}} ] }, {"property": "Status", "select": {"does_not_equal": "Done"}} ] }
undefined

4. Page Operations

4. 页面操作

Create Pages:
bash
undefined
创建页面:
bash
undefined

Create page in database

在数据库中创建页面

curl -s -X POST "https://api.notion.com/v1/pages"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{ "parent": {"database_id": "DATABASE_ID"}, "properties": { "Name": { "title": [{"text": {"content": "New Task"}}] }, "Status": { "select": {"name": "To Do"} }, "Priority": { "select": {"name": "High"} }, "Due Date": { "date": {"start": "2025-01-20"} } } }' | jq

**Python - Page Operations:**
```python
curl -s -X POST "https://api.notion.com/v1/pages"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-H "Content-Type: application/json"
-d '{ "parent": {"database_id": "DATABASE_ID"}, "properties": { "Name": { "title": [{"text": {"content": "New Task"}}] }, "Status": { "select": {"name": "To Do"} }, "Priority": { "select": {"name": "High"} }, "Due Date": { "date": {"start": "2025-01-20"} } } }' | jq

**Python - 页面操作:**
```python

Create page in database

在数据库中创建页面

new_page = notion.pages.create( parent={"database_id": "your-database-id"}, properties={ "Name": { "title": [{"text": {"content": "New Task"}}] }, "Status": { "select": {"name": "To Do"} }, "Priority": { "select": {"name": "High"} }, "Due Date": { "date": {"start": "2025-01-20", "end": "2025-01-25"} }, "Tags": { "multi_select": [ {"name": "development"}, {"name": "urgent"} ] }, "Assignee": { "people": [{"id": "user-id"}] }, "Notes": { "rich_text": [{"text": {"content": "Task description here"}}] }, "Completed": { "checkbox": False }, "Amount": { "number": 100 }, "URL": { "url": "https://example.com" }, "Email": { "email": "user@example.com" } } ) print(f"Created page: {new_page['id']}")
new_page = notion.pages.create( parent={"database_id": "your-database-id"}, properties={ "Name": { "title": [{"text": {"content": "New Task"}}] }, "Status": { "select": {"name": "To Do"} }, "Priority": { "select": {"name": "High"} }, "Due Date": { "date": {"start": "2025-01-20", "end": "2025-01-25"} }, "Tags": { "multi_select": [ {"name": "development"}, {"name": "urgent"} ] }, "Assignee": { "people": [{"id": "user-id"}] }, "Notes": { "rich_text": [{"text": {"content": "Task description here"}}] }, "Completed": { "checkbox": False }, "Amount": { "number": 100 }, "URL": { "url": "https://example.com" }, "Email": { "email": "user@example.com" } } ) print(f"Created page: {new_page['id']}")

Create page with content (blocks)

创建带内容的页面(块)

new_page = notion.pages.create( parent={"database_id": "your-database-id"}, properties={ "Name": {"title": [{"text": {"content": "Page with Content"}}]} }, children=[ { "object": "block", "type": "heading_2", "heading_2": { "rich_text": [{"type": "text", "text": {"content": "Overview"}}] } }, { "object": "block", "type": "paragraph", "paragraph": { "rich_text": [{"type": "text", "text": {"content": "This is the content."}}] } }, { "object": "block", "type": "to_do", "to_do": { "rich_text": [{"type": "text", "text": {"content": "Task item"}}], "checked": False } } ] )
new_page = notion.pages.create( parent={"database_id": "your-database-id"}, properties={ "Name": {"title": [{"text": {"content": "Page with Content"}}]} }, children=[ { "object": "block", "type": "heading_2", "heading_2": { "rich_text": [{"type": "text", "text": {"content": "Overview"}}] } }, { "object": "block", "type": "paragraph", "paragraph": { "rich_text": [{"type": "text", "text": {"content": "This is the content."}}] } }, { "object": "block", "type": "to_do", "to_do": { "rich_text": [{"type": "text", "text": {"content": "Task item"}}], "checked": False } } ] )

Retrieve page

获取页面

page = notion.pages.retrieve(page_id="page-id") print(f"Page: {page['properties']['Name']['title'][0]['plain_text']}")
page = notion.pages.retrieve(page_id="page-id") print(f"Page: {page['properties']['Name']['title'][0]['plain_text']}")

Update page properties

更新页面属性

notion.pages.update( page_id="page-id", properties={ "Status": {"select": {"name": "Done"}}, "Completed": {"checkbox": True} } )
notion.pages.update( page_id="page-id", properties={ "Status": {"select": {"name": "Done"}}, "Completed": {"checkbox": True} } )

Archive page (soft delete)

归档页面(软删除)

notion.pages.update( page_id="page-id", archived=True )
notion.pages.update( page_id="page-id", archived=True )

Restore page

恢复页面

notion.pages.update( page_id="page-id", archived=False )
undefined
notion.pages.update( page_id="page-id", archived=False )
undefined

5. Block Operations

5. 块操作

Block Types:
python
undefined
块类型:
python
undefined

Paragraph

段落

{ "type": "paragraph", "paragraph": { "rich_text": [{"type": "text", "text": {"content": "Text content"}}] } }
{ "type": "paragraph", "paragraph": { "rich_text": [{"type": "text", "text": {"content": "Text content"}}] } }

Headings

标题

{ "type": "heading_1", "heading_1": { "rich_text": [{"type": "text", "text": {"content": "Heading 1"}}] } }
{ "type": "heading_1", "heading_1": { "rich_text": [{"type": "text", "text": {"content": "Heading 1"}}] } }

Also: heading_2, heading_3

还有:heading_2, heading_3

Bulleted list

无序列表

{ "type": "bulleted_list_item", "bulleted_list_item": { "rich_text": [{"type": "text", "text": {"content": "List item"}}] } }
{ "type": "bulleted_list_item", "bulleted_list_item": { "rich_text": [{"type": "text", "text": {"content": "List item"}}] } }

Numbered list

有序列表

{ "type": "numbered_list_item", "numbered_list_item": { "rich_text": [{"type": "text", "text": {"content": "Item 1"}}] } }
{ "type": "numbered_list_item", "numbered_list_item": { "rich_text": [{"type": "text", "text": {"content": "Item 1"}}] } }

To-do

待办事项

{ "type": "to_do", "to_do": { "rich_text": [{"type": "text", "text": {"content": "Task"}}], "checked": False } }
{ "type": "to_do", "to_do": { "rich_text": [{"type": "text", "text": {"content": "Task"}}], "checked": False } }

Toggle

折叠块

{ "type": "toggle", "toggle": { "rich_text": [{"type": "text", "text": {"content": "Toggle header"}}], "children": [] # Nested blocks } }
{ "type": "toggle", "toggle": { "rich_text": [{"type": "text", "text": {"content": "Toggle header"}}], "children": [] # 嵌套块 } }

Code block

代码块

{ "type": "code", "code": { "rich_text": [{"type": "text", "text": {"content": "print('hello')"}}], "language": "python" } }
{ "type": "code", "code": { "rich_text": [{"type": "text", "text": {"content": "print('hello')"}}], "language": "python" } }

Quote

引用

{ "type": "quote", "quote": { "rich_text": [{"type": "text", "text": {"content": "Quote text"}}] } }
{ "type": "quote", "quote": { "rich_text": [{"type": "text", "text": {"content": "Quote text"}}] } }

Callout

提示框

{ "type": "callout", "callout": { "rich_text": [{"type": "text", "text": {"content": "Important note"}}], "icon": {"emoji": "💡"} } }
{ "type": "callout", "callout": { "rich_text": [{"type": "text", "text": {"content": "Important note"}}], "icon": {"emoji": "💡"} } }

Divider

分割线

{ "type": "divider", "divider": {} }
{ "type": "divider", "divider": {} }

Table of contents

目录

{ "type": "table_of_contents", "table_of_contents": {} }

**Python - Block Operations:**
```python
{ "type": "table_of_contents", "table_of_contents": {} }

**Python - 块操作:**
```python

Get page blocks (children)

获取页面块(子元素)

blocks = notion.blocks.children.list(block_id="page-id") for block in blocks["results"]: print(f"Block type: {block['type']}")
blocks = notion.blocks.children.list(block_id="page-id") for block in blocks["results"]: print(f"Block type: {block['type']}")

Append blocks to page

向页面追加块

notion.blocks.children.append( block_id="page-id", children=[ { "object": "block", "type": "heading_2", "heading_2": { "rich_text": [{"type": "text", "text": {"content": "New Section"}}] } }, { "object": "block", "type": "paragraph", "paragraph": { "rich_text": [ {"type": "text", "text": {"content": "Some "}}, {"type": "text", "text": {"content": "bold"}, "annotations": {"bold": True}}, {"type": "text", "text": {"content": " text."}} ] } }, { "object": "block", "type": "bulleted_list_item", "bulleted_list_item": { "rich_text": [{"type": "text", "text": {"content": "First item"}}] } }, { "object": "block", "type": "bulleted_list_item", "bulleted_list_item": { "rich_text": [{"type": "text", "text": {"content": "Second item"}}] } } ] )
notion.blocks.children.append( block_id="page-id", children=[ { "object": "block", "type": "heading_2", "heading_2": { "rich_text": [{"type": "text", "text": {"content": "New Section"}}] } }, { "object": "block", "type": "paragraph", "paragraph": { "rich_text": [ {"type": "text", "text": {"content": "Some "}}, {"type": "text", "text": {"content": "bold"}, "annotations": {"bold": True}}, {"type": "text", "text": {"content": " text."}} ] } }, { "object": "block", "type": "bulleted_list_item", "bulleted_list_item": { "rich_text": [{"type": "text", "text": {"content": "First item"}}] } }, { "object": "block", "type": "bulleted_list_item", "bulleted_list_item": { "rich_text": [{"type": "text", "text": {"content": "Second item"}}] } } ] )

Update block

更新块

notion.blocks.update( block_id="block-id", paragraph={ "rich_text": [{"type": "text", "text": {"content": "Updated content"}}] } )
notion.blocks.update( block_id="block-id", paragraph={ "rich_text": [{"type": "text", "text": {"content": "Updated content"}}] } )

Delete block

删除块

notion.blocks.delete(block_id="block-id")
notion.blocks.delete(block_id="block-id")

Get all blocks recursively

递归获取所有块

def get_all_blocks(block_id): """Recursively get all blocks""" all_blocks = [] has_more = True start_cursor = None
while has_more:
    response = notion.blocks.children.list(
        block_id=block_id,
        start_cursor=start_cursor,
        page_size=100
    )
    for block in response["results"]:
        all_blocks.append(block)
        if block.get("has_children"):
            children = get_all_blocks(block["id"])
            all_blocks.extend(children)
    has_more = response["has_more"]
    start_cursor = response.get("next_cursor")

return all_blocks
all_blocks = get_all_blocks("page-id") print(f"Total blocks: {len(all_blocks)}")
undefined
def get_all_blocks(block_id): """递归获取所有块""" all_blocks = [] has_more = True start_cursor = None
while has_more:
    response = notion.blocks.children.list(
        block_id=block_id,
        start_cursor=start_cursor,
        page_size=100
    )
    for block in response["results"]:
        all_blocks.append(block)
        if block.get("has_children"):
            children = get_all_blocks(block["id"])
            all_blocks.extend(children)
    has_more = response["has_more"]
    start_cursor = response.get("next_cursor")

return all_blocks
all_blocks = get_all_blocks("page-id") print(f"Total blocks: {len(all_blocks)}")
undefined

6. Rich Text Formatting

6. 富文本格式化

Rich Text Structure:
python
undefined
富文本结构:
python
undefined

Basic text

基础文本

{"type": "text", "text": {"content": "Plain text"}}
{"type": "text", "text": {"content": "Plain text"}}

Styled text

带样式的文本

{ "type": "text", "text": {"content": "Styled text"}, "annotations": { "bold": True, "italic": False, "strikethrough": False, "underline": False, "code": False, "color": "red" # default, gray, brown, orange, yellow, green, blue, purple, pink, red } }
{ "type": "text", "text": {"content": "Styled text"}, "annotations": { "bold": True, "italic": False, "strikethrough": False, "underline": False, "code": False, "color": "red" # default, gray, brown, orange, yellow, green, blue, purple, pink, red } }

Link

链接

{ "type": "text", "text": { "content": "Click here", "link": {"url": "https://example.com"} } }
{ "type": "text", "text": { "content": "Click here", "link": {"url": "https://example.com"} } }

Mention user

提及用户

{ "type": "mention", "mention": { "type": "user", "user": {"id": "user-id"} } }
{ "type": "mention", "mention": { "type": "user", "user": {"id": "user-id"} } }

Mention page

提及页面

{ "type": "mention", "mention": { "type": "page", "page": {"id": "page-id"} } }
{ "type": "mention", "mention": { "type": "page", "page": {"id": "page-id"} } }

Mention date

提及日期

{ "type": "mention", "mention": { "type": "date", "date": {"start": "2025-01-17"} } }
{ "type": "mention", "mention": { "type": "date", "date": {"start": "2025-01-17"} } }

Equation

公式

{ "type": "equation", "equation": {"expression": "E = mc^2"} }

**Python - Rich Text Helper:**
```python
def create_rich_text(text, bold=False, italic=False, code=False, color="default", link=None):
    """Helper to create rich text objects"""
    rt = {
        "type": "text",
        "text": {"content": text},
        "annotations": {
            "bold": bold,
            "italic": italic,
            "strikethrough": False,
            "underline": False,
            "code": code,
            "color": color
        }
    }
    if link:
        rt["text"]["link"] = {"url": link}
    return rt
{ "type": "equation", "equation": {"expression": "E = mc^2"} }

**Python - 富文本辅助函数:**
```python
def create_rich_text(text, bold=False, italic=False, code=False, color="default", link=None):
    """创建富文本对象的辅助函数"""
    rt = {
        "type": "text",
        "text": {"content": text},
        "annotations": {
            "bold": bold,
            "italic": italic,
            "strikethrough": False,
            "underline": False,
            "code": code,
            "color": color
        }
    }
    if link:
        rt["text"]["link"] = {"url": link}
    return rt

Usage

使用示例

paragraph_content = [ create_rich_text("This is "), create_rich_text("bold", bold=True), create_rich_text(" and "), create_rich_text("italic", italic=True), create_rich_text(" text with a "), create_rich_text("link", link="https://example.com"), create_rich_text(".") ]
notion.blocks.children.append( block_id="page-id", children=[{ "type": "paragraph", "paragraph": {"rich_text": paragraph_content} }] )
undefined
paragraph_content = [ create_rich_text("This is "), create_rich_text("bold", bold=True), create_rich_text(" and "), create_rich_text("italic", italic=True), create_rich_text(" text with a "), create_rich_text("link", link="https://example.com"), create_rich_text(".") ]
notion.blocks.children.append( block_id="page-id", children=[{ "type": "paragraph", "paragraph": {"rich_text": paragraph_content} }] )
undefined

7. Relations and Rollups

7. 关联与汇总

Create Related Databases:
python
undefined
创建关联数据库:
python
undefined

Create Projects database

创建项目数据库

projects_db = notion.databases.create( parent={"type": "page_id", "page_id": "parent-page-id"}, title=[{"type": "text", "text": {"content": "Projects"}}], properties={ "Name": {"title": {}}, "Status": { "select": { "options": [ {"name": "Active", "color": "green"}, {"name": "Completed", "color": "gray"} ] } } } )
projects_db = notion.databases.create( parent={"type": "page_id", "page_id": "parent-page-id"}, title=[{"type": "text", "text": {"content": "Projects"}}], properties={ "Name": {"title": {}}, "Status": { "select": { "options": [ {"name": "Active", "color": "green"}, {"name": "Completed", "color": "gray"} ] } } } )

Create Tasks database with relation to Projects

创建与项目关联的任务数据库

tasks_db = notion.databases.create( parent={"type": "page_id", "page_id": "parent-page-id"}, title=[{"type": "text", "text": {"content": "Tasks"}}], properties={ "Name": {"title": {}}, "Status": { "select": { "options": [ {"name": "To Do", "color": "gray"}, {"name": "Done", "color": "green"} ] } }, "Project": { "relation": { "database_id": projects_db["id"], "single_property": {} } } } )
tasks_db = notion.databases.create( parent={"type": "page_id", "page_id": "parent-page-id"}, title=[{"type": "text", "text": {"content": "Tasks"}}], properties={ "Name": {"title": {}}, "Status": { "select": { "options": [ {"name": "To Do", "color": "gray"}, {"name": "Done", "color": "green"} ] } }, "Project": { "relation": { "database_id": projects_db["id"], "single_property": {} } } } )

Add rollup to Projects for task count

在项目数据库中添加任务数量汇总属性

notion.databases.update( database_id=projects_db["id"], properties={ "Task Count": { "rollup": { "relation_property_name": "Tasks", # This is auto-created "rollup_property_name": "Name", "function": "count" } } } )
notion.databases.update( database_id=projects_db["id"], properties={ "Task Count": { "rollup": { "relation_property_name": "Tasks", # 自动创建 "rollup_property_name": "Name", "function": "count" } } } )

Create task linked to project

创建关联到项目的任务

notion.pages.create( parent={"database_id": tasks_db["id"]}, properties={ "Name": {"title": [{"text": {"content": "Task 1"}}]}, "Status": {"select": {"name": "To Do"}}, "Project": {"relation": [{"id": "project-page-id"}]} } )
undefined
notion.pages.create( parent={"database_id": tasks_db["id"]}, properties={ "Name": {"title": [{"text": {"content": "Task 1"}}]}, "Status": {"select": {"name": "To Do"}}, "Project": {"relation": [{"id": "project-page-id"}]} } )
undefined

8. Search API

8. 搜索API

Search Operations:
python
undefined
搜索操作:
python
undefined

Search all

搜索所有内容

results = notion.search() print(f"Total accessible items: {len(results['results'])}")
results = notion.search() print(f"Total accessible items: {len(results['results'])}")

Search with query

带关键词搜索

results = notion.search(query="project plan") for item in results["results"]: obj_type = item["object"] if obj_type == "page": title = item["properties"].get("title", {}).get("title", [{}])[0].get("plain_text", "Untitled") elif obj_type == "database": title = item["title"][0]["plain_text"] if item["title"] else "Untitled" print(f"{obj_type}: {title}")
results = notion.search(query="project plan") for item in results["results"]: obj_type = item["object"] if obj_type == "page": title = item["properties"].get("title", {}).get("title", [{}])[0].get("plain_text", "Untitled") elif obj_type == "database": title = item["title"][0]["plain_text"] if item["title"] else "Untitled" print(f"{obj_type}: {title}")

Search only pages

仅搜索页面

results = notion.search( query="meeting", filter={"property": "object", "value": "page"} )
results = notion.search( query="meeting", filter={"property": "object", "value": "page"} )

Search only databases

仅搜索数据库

results = notion.search( filter={"property": "object", "value": "database"} )
results = notion.search( filter={"property": "object", "value": "database"} )

Search with sorting

带排序的搜索

results = notion.search( query="report", sort={ "direction": "descending", "timestamp": "last_edited_time" } )
results = notion.search( query="report", sort={ "direction": "descending", "timestamp": "last_edited_time" } )

Paginated search

分页搜索

def search_all(query=None, filter=None): """Search with pagination""" all_results = [] has_more = True start_cursor = None
while has_more:
    response = notion.search(
        query=query,
        filter=filter,
        start_cursor=start_cursor,
        page_size=100
    )
    all_results.extend(response["results"])
    has_more = response["has_more"]
    start_cursor = response.get("next_cursor")

return all_results
undefined
def search_all(query=None, filter=None): """分页搜索所有内容""" all_results = [] has_more = True start_cursor = None
while has_more:
    response = notion.search(
        query=query,
        filter=filter,
        start_cursor=start_cursor,
        page_size=100
    )
    all_results.extend(response["results"])
    has_more = response["has_more"]
    start_cursor = response.get("next_cursor")

return all_results
undefined

Complete Examples

完整示例

Example 1: Task Management System

示例1:任务管理系统

python
#!/usr/bin/env python3
"""notion_tasks.py - Complete task management with Notion"""

from notion_client import Client
from datetime import datetime, timedelta
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])

class NotionTaskManager:
    def __init__(self, database_id):
        self.database_id = database_id

    def create_task(self, name, status="To Do", priority="Medium",
                    due_date=None, tags=None, notes=None):
        """Create a new task"""
        properties = {
            "Name": {"title": [{"text": {"content": name}}]},
            "Status": {"select": {"name": status}},
            "Priority": {"select": {"name": priority}}
        }

        if due_date:
            properties["Due Date"] = {"date": {"start": due_date}}

        if tags:
            properties["Tags"] = {
                "multi_select": [{"name": tag} for tag in tags]
            }

        if notes:
            properties["Notes"] = {
                "rich_text": [{"text": {"content": notes}}]
            }

        return notion.pages.create(
            parent={"database_id": self.database_id},
            properties=properties
        )

    def get_tasks_by_status(self, status):
        """Get all tasks with given status"""
        return notion.databases.query(
            database_id=self.database_id,
            filter={
                "property": "Status",
                "select": {"equals": status}
            }
        )

    def get_overdue_tasks(self):
        """Get all overdue tasks"""
        today = datetime.now().strftime("%Y-%m-%d")
        return notion.databases.query(
            database_id=self.database_id,
            filter={
                "and": [
                    {"property": "Due Date", "date": {"before": today}},
                    {"property": "Status", "select": {"does_not_equal": "Done"}}
                ]
            }
        )

    def get_high_priority_tasks(self):
        """Get high priority incomplete tasks"""
        return notion.databases.query(
            database_id=self.database_id,
            filter={
                "and": [
                    {"property": "Priority", "select": {"equals": "High"}},
                    {"property": "Status", "select": {"does_not_equal": "Done"}}
                ]
            },
            sorts=[
                {"property": "Due Date", "direction": "ascending"}
            ]
        )

    def complete_task(self, page_id):
        """Mark task as done"""
        return notion.pages.update(
            page_id=page_id,
            properties={
                "Status": {"select": {"name": "Done"}},
                "Completed": {"checkbox": True}
            }
        )

    def update_task_status(self, page_id, status):
        """Update task status"""
        return notion.pages.update(
            page_id=page_id,
            properties={
                "Status": {"select": {"name": status}}
            }
        )

    def get_weekly_summary(self):
        """Get summary for the week"""
        week_ago = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")

        # Completed this week
        completed = notion.databases.query(
            database_id=self.database_id,
            filter={
                "and": [
                    {"property": "Status", "select": {"equals": "Done"}},
                    {"property": "Last edited time", "date": {"after": week_ago}}
                ]
            }
        )

        # Due this week
        next_week = (datetime.now() + timedelta(days=7)).strftime("%Y-%m-%d")
        upcoming = notion.databases.query(
            database_id=self.database_id,
            filter={
                "and": [
                    {"property": "Due Date", "date": {"on_or_before": next_week}},
                    {"property": "Status", "select": {"does_not_equal": "Done"}}
                ]
            }
        )

        return {
            "completed_count": len(completed["results"]),
            "upcoming_count": len(upcoming["results"]),
            "completed": completed["results"],
            "upcoming": upcoming["results"]
        }
python
#!/usr/bin/env python3
"""notion_tasks.py - 基于Notion的完整任务管理系统"""

from notion_client import Client
from datetime import datetime, timedelta
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])

class NotionTaskManager:
    def __init__(self, database_id):
        self.database_id = database_id

    def create_task(self, name, status="To Do", priority="Medium",
                    due_date=None, tags=None, notes=None):
        """创建新任务"""
        properties = {
            "Name": {"title": [{"text": {"content": name}}]},
            "Status": {"select": {"name": status}},
            "Priority": {"select": {"name": priority}}
        }

        if due_date:
            properties["Due Date"] = {"date": {"start": due_date}}

        if tags:
            properties["Tags"] = {
                "multi_select": [{"name": tag} for tag in tags]
            }

        if notes:
            properties["Notes"] = {
                "rich_text": [{"text": {"content": notes}}]
            }

        return notion.pages.create(
            parent={"database_id": self.database_id},
            properties=properties
        )

    def get_tasks_by_status(self, status):
        """获取指定状态的所有任务"""
        return notion.databases.query(
            database_id=self.database_id,
            filter={
                "property": "Status",
                "select": {"equals": status}
            }
        )

    def get_overdue_tasks(self):
        """获取所有逾期任务"""
        today = datetime.now().strftime("%Y-%m-%d")
        return notion.databases.query(
            database_id=self.database_id,
            filter={
                "and": [
                    {"property": "Due Date", "date": {"before": today}},
                    {"property": "Status", "select": {"does_not_equal": "Done"}}
                ]
            }
        )

    def get_high_priority_tasks(self):
        """获取高优先级未完成任务"""
        return notion.databases.query(
            database_id=self.database_id,
            filter={
                "and": [
                    {"property": "Priority", "select": {"equals": "High"}},
                    {"property": "Status", "select": {"does_not_equal": "Done"}}
                ]
            },
            sorts=[
                {"property": "Due Date", "direction": "ascending"}
            ]
        )

    def complete_task(self, page_id):
        """标记任务为完成"""
        return notion.pages.update(
            page_id=page_id,
            properties={
                "Status": {"select": {"name": "Done"}},
                "Completed": {"checkbox": True}
            }
        )

    def update_task_status(self, page_id, status):
        """更新任务状态"""
        return notion.pages.update(
            page_id=page_id,
            properties={
                "Status": {"select": {"name": status}}
            }
        )

    def get_weekly_summary(self):
        """获取本周任务汇总"""
        week_ago = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")

        # 本周完成的任务
        completed = notion.databases.query(
            database_id=self.database_id,
            filter={
                "and": [
                    {"property": "Status", "select": {"equals": "Done"}},
                    {"property": "Last edited time", "date": {"after": week_ago}}
                ]
            }
        )

        # 本周到期的任务
        next_week = (datetime.now() + timedelta(days=7)).strftime("%Y-%m-%d")
        upcoming = notion.databases.query(
            database_id=self.database_id,
            filter={
                "and": [
                    {"property": "Due Date", "date": {"on_or_before": next_week}},
                    {"property": "Status", "select": {"does_not_equal": "Done"}}
                ]
            }
        )

        return {
            "completed_count": len(completed["results"]),
            "upcoming_count": len(upcoming["results"]),
            "completed": completed["results"],
            "upcoming": upcoming["results"]
        }

Usage

使用示例

if name == "main": tm = NotionTaskManager("your-database-id")
# Create task
task = tm.create_task(
    name="Review Q1 report",
    priority="High",
    due_date="2025-01-20",
    tags=["work", "quarterly"],
    notes="Review and provide feedback"
)
print(f"Created task: {task['id']}")

# Get overdue tasks
overdue = tm.get_overdue_tasks()
print(f"\nOverdue tasks: {len(overdue['results'])}")
for t in overdue["results"]:
    name = t["properties"]["Name"]["title"][0]["plain_text"]
    print(f"  - {name}")

# Weekly summary
summary = tm.get_weekly_summary()
print(f"\nWeekly Summary:")
print(f"  Completed: {summary['completed_count']}")
print(f"  Upcoming: {summary['upcoming_count']}")
undefined
if name == "main": tm = NotionTaskManager("your-database-id")
# 创建任务
task = tm.create_task(
    name="Review Q1 report",
    priority="High",
    due_date="2025-01-20",
    tags=["work", "quarterly"],
    notes="Review and provide feedback"
)
print(f"Created task: {task['id']}")

# 获取逾期任务
overdue = tm.get_overdue_tasks()
print(f"\nOverdue tasks: {len(overdue['results'])}")
for t in overdue["results"]:
    name = t["properties"]["Name"]["title"][0]["plain_text"]
    print(f"  - {name}")

# 本周汇总
summary = tm.get_weekly_summary()
print(f"\nWeekly Summary:")
print(f"  Completed: {summary['completed_count']}")
print(f"  Upcoming: {summary['upcoming_count']}")
undefined

Example 2: Content Management System

�示例2:内容管理系统

python
#!/usr/bin/env python3
"""notion_cms.py - Content management with Notion"""

from notion_client import Client
from datetime import datetime
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])

class NotionCMS:
    def __init__(self, content_db_id, categories_db_id=None):
        self.content_db_id = content_db_id
        self.categories_db_id = categories_db_id

    def create_article(self, title, content_blocks, status="Draft",
                       category=None, tags=None, author=None):
        """Create a new article"""
        properties = {
            "Title": {"title": [{"text": {"content": title}}]},
            "Status": {"select": {"name": status}},
            "Created": {"date": {"start": datetime.now().isoformat()}}
        }

        if category:
            properties["Category"] = {"select": {"name": category}}

        if tags:
            properties["Tags"] = {
                "multi_select": [{"name": tag} for tag in tags]
            }

        if author:
            properties["Author"] = {
                "rich_text": [{"text": {"content": author}}]
            }

        return notion.pages.create(
            parent={"database_id": self.content_db_id},
            properties=properties,
            children=content_blocks
        )

    def create_article_with_template(self, title, template="blog"):
        """Create article from template"""
        templates = {
            "blog": [
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Introduction"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Main Content"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Conclusion"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
            ],
            "tutorial": [
                {"type": "callout", "callout": {
                    "rich_text": [{"text": {"content": "Prerequisites: "}}],
                    "icon": {"emoji": "📋"}
                }},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Overview"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Step 1"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "code", "code": {"rich_text": [{"text": {"content": "# code here"}}], "language": "python"}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Step 2"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Summary"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
            ]
        }

        return self.create_article(
            title=title,
            content_blocks=templates.get(template, templates["blog"]),
            status="Draft"
        )

    def get_published_articles(self, category=None, limit=10):
        """Get published articles"""
        filter_conditions = [
            {"property": "Status", "select": {"equals": "Published"}}
        ]

        if category:
            filter_conditions.append(
                {"property": "Category", "select": {"equals": category}}
            )

        return notion.databases.query(
            database_id=self.content_db_id,
            filter={"and": filter_conditions} if len(filter_conditions) > 1 else filter_conditions[0],
            sorts=[{"property": "Created", "direction": "descending"}],
            page_size=limit
        )

    def publish_article(self, page_id):
        """Publish an article"""
        return notion.pages.update(
            page_id=page_id,
            properties={
                "Status": {"select": {"name": "Published"}},
                "Published Date": {"date": {"start": datetime.now().isoformat()}}
            }
        )

    def export_article_to_markdown(self, page_id):
        """Export article content to markdown"""
        page = notion.pages.retrieve(page_id)
        blocks = notion.blocks.children.list(block_id=page_id)

        title = page["properties"]["Title"]["title"][0]["plain_text"]
        markdown = f"# {title}\n\n"

        for block in blocks["results"]:
            markdown += self._block_to_markdown(block)

        return markdown

    def _block_to_markdown(self, block):
        """Convert block to markdown"""
        block_type = block["type"]

        if block_type == "paragraph":
            text = self._rich_text_to_markdown(block["paragraph"]["rich_text"])
            return f"{text}\n\n"
        elif block_type == "heading_1":
            text = self._rich_text_to_markdown(block["heading_1"]["rich_text"])
            return f"# {text}\n\n"
        elif block_type == "heading_2":
            text = self._rich_text_to_markdown(block["heading_2"]["rich_text"])
            return f"## {text}\n\n"
        elif block_type == "heading_3":
            text = self._rich_text_to_markdown(block["heading_3"]["rich_text"])
            return f"### {text}\n\n"
        elif block_type == "bulleted_list_item":
            text = self._rich_text_to_markdown(block["bulleted_list_item"]["rich_text"])
            return f"- {text}\n"
        elif block_type == "numbered_list_item":
            text = self._rich_text_to_markdown(block["numbered_list_item"]["rich_text"])
            return f"1. {text}\n"
        elif block_type == "code":
            text = self._rich_text_to_markdown(block["code"]["rich_text"])
            lang = block["code"]["language"]
            return f"```{lang}\n{text}\n```\n\n"
        elif block_type == "quote":
            text = self._rich_text_to_markdown(block["quote"]["rich_text"])
            return f"> {text}\n\n"
        elif block_type == "divider":
            return "---\n\n"

        return ""

    def _rich_text_to_markdown(self, rich_text):
        """Convert rich text array to markdown"""
        result = ""
        for rt in rich_text:
            text = rt.get("text", {}).get("content", "")
            annotations = rt.get("annotations", {})

            if annotations.get("bold"):
                text = f"**{text}**"
            if annotations.get("italic"):
                text = f"*{text}*"
            if annotations.get("code"):
                text = f"`{text}`"
            if annotations.get("strikethrough"):
                text = f"~~{text}~~"

            link = rt.get("text", {}).get("link")
            if link:
                text = f"[{text}]({link['url']})"

            result += text
        return result
python
#!/usr/bin/env python3
"""notion_cms.py - 基于Notion的内容管理系统"""

from notion_client import Client
from datetime import datetime
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])

class NotionCMS:
    def __init__(self, content_db_id, categories_db_id=None):
        self.content_db_id = content_db_id
        self.categories_db_id = categories_db_id

    def create_article(self, title, content_blocks, status="Draft",
                       category=None, tags=None, author=None):
        """创建新文章"""
        properties = {
            "Title": {"title": [{"text": {"content": title}}]},
            "Status": {"select": {"name": status}},
            "Created": {"date": {"start": datetime.now().isoformat()}}
        }

        if category:
            properties["Category"] = {"select": {"name": category}}

        if tags:
            properties["Tags"] = {
                "multi_select": [{"name": tag} for tag in tags]
            }

        if author:
            properties["Author"] = {
                "rich_text": [{"text": {"content": author}}]
            }

        return notion.pages.create(
            parent={"database_id": self.content_db_id},
            properties=properties,
            children=content_blocks
        )

    def create_article_with_template(self, title, template="blog"):
        """通过模板创建文章"""
        templates = {
            "blog": [
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Introduction"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Main Content"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Conclusion"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
            ],
            "tutorial": [
                {"type": "callout", "callout": {
                    "rich_text": [{"text": {"content": "Prerequisites: "}}],
                    "icon": {"emoji": "📋"}
                }},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Overview"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Step 1"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "code", "code": {"rich_text": [{"text": {"content": "# code here"}}], "language": "python"}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Step 2"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
                {"type": "heading_2", "heading_2": {"rich_text": [{"text": {"content": "Summary"}}]}},
                {"type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": ""}}]}},
            ]
        }

        return self.create_article(
            title=title,
            content_blocks=templates.get(template, templates["blog"]),
            status="Draft"
        )

    def get_published_articles(self, category=None, limit=10):
        """获取已发布文章"""
        filter_conditions = [
            {"property": "Status", "select": {"equals": "Published"}}
        ]

        if category:
            filter_conditions.append(
                {"property": "Category", "select": {"equals": category}}
            )

        return notion.databases.query(
            database_id=self.content_db_id,
            filter={"and": filter_conditions} if len(filter_conditions) > 1 else filter_conditions[0],
            sorts=[{"property": "Created", "direction": "descending"}],
            page_size=limit
        )

    def publish_article(self, page_id):
        """发布文章"""
        return notion.pages.update(
            page_id=page_id,
            properties={
                "Status": {"select": {"name": "Published"}},
                "Published Date": {"date": {"start": datetime.now().isoformat()}}
            }
        )

    def export_article_to_markdown(self, page_id):
        """将文章内容导出为Markdown"""
        page = notion.pages.retrieve(page_id)
        blocks = notion.blocks.children.list(block_id=page_id)

        title = page["properties"]["Title"]["title"][0]["plain_text"]
        markdown = f"# {title}\n\n"

        for block in blocks["results"]:
            markdown += self._block_to_markdown(block)

        return markdown

    def _block_to_markdown(self, block):
        """将块转换为Markdown格式"""
        block_type = block["type"]

        if block_type == "paragraph":
            text = self._rich_text_to_markdown(block["paragraph"]["rich_text"])
            return f"{text}\n\n"
        elif block_type == "heading_1":
            text = self._rich_text_to_markdown(block["heading_1"]["rich_text"])
            return f"# {text}\n\n"
        elif block_type == "heading_2":
            text = self._rich_text_to_markdown(block["heading_2"]["rich_text"])
            return f"## {text}\n\n"
        elif block_type == "heading_3":
            text = self._rich_text_to_markdown(block["heading_3"]["rich_text"])
            return f"### {text}\n\n"
        elif block_type == "bulleted_list_item":
            text = self._rich_text_to_markdown(block["bulleted_list_item"]["rich_text"])
            return f"- {text}\n"
        elif block_type == "numbered_list_item":
            text = self._rich_text_to_markdown(block["numbered_list_item"]["rich_text"])
            return f"1. {text}\n"
        elif block_type == "code":
            text = self._rich_text_to_markdown(block["code"]["rich_text"])
            lang = block["code"]["language"]
            return f"```{lang}\n{text}\n```\n\n"
        elif block_type == "quote":
            text = self._rich_text_to_markdown(block["quote"]["rich_text"])
            return f"> {text}\n\n"
        elif block_type == "divider":
            return "---\n\n"

        return ""

    def _rich_text_to_markdown(self, rich_text):
        """将富文本数组转换为Markdown格式"""
        result = ""
        for rt in rich_text:
            text = rt.get("text", {}).get("content", "")
            annotations = rt.get("annotations", {})

            if annotations.get("bold"):
                text = f"**{text}**"
            if annotations.get("italic"):
                text = f"*{text}*"
            if annotations.get("code"):
                text = f"`{text}`"
            if annotations.get("strikethrough"):
                text = f"~~{text}~~"

            link = rt.get("text", {}).get("link")
            if link:
                text = f"[{text}]({link['url']})"

            result += text
        return result

Usage

使用示例

if name == "main": cms = NotionCMS("your-content-database-id")
# Create article from template
article = cms.create_article_with_template(
    title="Getting Started with Python",
    template="tutorial"
)
print(f"Created article: {article['id']}")

# Get published articles
published = cms.get_published_articles(limit=5)
print(f"\nPublished articles: {len(published['results'])}")

# Export to markdown
md = cms.export_article_to_markdown("article-page-id")
print(md)
undefined
if name == "main": cms = NotionCMS("your-content-database-id")
# 通过模板创建文章
article = cms.create_article_with_template(
    title="Getting Started with Python",
    template="tutorial"
)
print(f"Created article: {article['id']}")

# 获取已发布文章
published = cms.get_published_articles(limit=5)
print(f"\nPublished articles: {len(published['results'])}")

# 导出为Markdown
md = cms.export_article_to_markdown("article-page-id")
print(md)
undefined

Example 3: Project Dashboard

示例3:项目仪表板

python
#!/usr/bin/env python3
"""notion_dashboard.py - Project dashboard with Notion"""

from notion_client import Client
from datetime import datetime, timedelta
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])

def generate_project_dashboard(projects_db_id, tasks_db_id):
    """Generate project dashboard data"""

    # Get all active projects
    projects = notion.databases.query(
        database_id=projects_db_id,
        filter={
            "property": "Status",
            "select": {"equals": "Active"}
        }
    )

    dashboard_data = []

    for project in projects["results"]:
        project_id = project["id"]
        project_name = project["properties"]["Name"]["title"][0]["plain_text"]

        # Get tasks for this project
        tasks = notion.databases.query(
            database_id=tasks_db_id,
            filter={
                "property": "Project",
                "relation": {"contains": project_id}
            }
        )

        # Calculate metrics
        total_tasks = len(tasks["results"])
        completed = sum(1 for t in tasks["results"]
                       if t["properties"]["Status"]["select"]["name"] == "Done")
        in_progress = sum(1 for t in tasks["results"]
                        if t["properties"]["Status"]["select"]["name"] == "In Progress")

        # Get overdue tasks
        today = datetime.now().strftime("%Y-%m-%d")
        overdue = sum(1 for t in tasks["results"]
                     if t["properties"].get("Due Date", {}).get("date", {}).get("start", "9999-99-99") < today
                     and t["properties"]["Status"]["select"]["name"] != "Done")

        dashboard_data.append({
            "project_id": project_id,
            "project_name": project_name,
            "total_tasks": total_tasks,
            "completed": completed,
            "in_progress": in_progress,
            "pending": total_tasks - completed - in_progress,
            "overdue": overdue,
            "completion_rate": round(completed / total_tasks * 100, 1) if total_tasks > 0 else 0
        })

    return dashboard_data

def create_dashboard_page(parent_page_id, dashboard_data):
    """Create a dashboard page with metrics"""

    # Build blocks for dashboard
    blocks = [
        {
            "type": "heading_1",
            "heading_1": {
                "rich_text": [{"text": {"content": f"Project Dashboard - {datetime.now().strftime('%Y-%m-%d')}"}}]
            }
        },
        {
            "type": "divider",
            "divider": {}
        }
    ]

    for project in dashboard_data:
        blocks.extend([
            {
                "type": "heading_2",
                "heading_2": {
                    "rich_text": [{"text": {"content": project["project_name"]}}]
                }
            },
            {
                "type": "callout",
                "callout": {
                    "rich_text": [{
                        "text": {
                            "content": f"Completion: {project['completion_rate']}% | "
                                      f"Tasks: {project['completed']}/{project['total_tasks']} | "
                                      f"In Progress: {project['in_progress']} | "
                                      f"Overdue: {project['overdue']}"
                        }
                    }],
                    "icon": {"emoji": "📊"}
                }
            }
        ])

        # Add progress bar representation
        progress = int(project['completion_rate'] / 10)
        progress_bar = "🟩" * progress + "⬜" * (10 - progress)
        blocks.append({
            "type": "paragraph",
            "paragraph": {
                "rich_text": [{"text": {"content": f"Progress: {progress_bar}"}}]
            }
        })

    # Create the page
    return notion.pages.create(
        parent={"page_id": parent_page_id},
        properties={
            "title": {"title": [{"text": {"content": "Project Dashboard"}}]}
        },
        children=blocks
    )
python
#!/usr/bin/env python3
"""notion_dashboard.py - 基于Notion的项目仪表板"""

from notion_client import Client
from datetime import datetime, timedelta
import os

notion = Client(auth=os.environ["NOTION_API_KEY"])

def generate_project_dashboard(projects_db_id, tasks_db_id):
    """生成项目仪表板数据"""

    # 获取所有活跃项目
    projects = notion.databases.query(
        database_id=projects_db_id,
        filter={
            "property": "Status",
            "select": {"equals": "Active"}
        }
    )

    dashboard_data = []

    for project in projects["results"]:
        project_id = project["id"]
        project_name = project["properties"]["Name"]["title"][0]["plain_text"]

        # 获取该项目的任务
        tasks = notion.databases.query(
            database_id=tasks_db_id,
            filter={
                "property": "Project",
                "relation": {"contains": project_id}
            }
        )

        # 计算指标
        total_tasks = len(tasks["results"])
        completed = sum(1 for t in tasks["results"]
                       if t["properties"]["Status"]["select"]["name"] == "Done")
        in_progress = sum(1 for t in tasks["results"]
                        if t["properties"]["Status"]["select"]["name"] == "In Progress")

        # 获取逾期任务
        today = datetime.now().strftime("%Y-%m-%d")
        overdue = sum(1 for t in tasks["results"]
                     if t["properties"].get("Due Date", {}).get("date", {}).get("start", "9999-99-99") < today
                     and t["properties"]["Status"]["select"]["name"] != "Done")

        dashboard_data.append({
            "project_id": project_id,
            "project_name": project_name,
            "total_tasks": total_tasks,
            "completed": completed,
            "in_progress": in_progress,
            "pending": total_tasks - completed - in_progress,
            "overdue": overdue,
            "completion_rate": round(completed / total_tasks * 100, 1) if total_tasks > 0 else 0
        })

    return dashboard_data

def create_dashboard_page(parent_page_id, dashboard_data):
    """创建包含指标的仪表板页面"""

    # 构建仪表板块
    blocks = [
        {
            "type": "heading_1",
            "heading_1": {
                "rich_text": [{"text": {"content": f"Project Dashboard - {datetime.now().strftime('%Y-%m-%d')}"}}]
            }
        },
        {
            "type": "divider",
            "divider": {}
        }
    ]

    for project in dashboard_data:
        blocks.extend([
            {
                "type": "heading_2",
                "heading_2": {
                    "rich_text": [{"text": {"content": project["project_name"]}}]
                }
            },
            {
                "type": "callout",
                "callout": {
                    "rich_text": [{
                        "text": {
                            "content": f"Completion: {project['completion_rate']}% | "
                                      f"Tasks: {project['completed']}/{project['total_tasks']} | "
                                      f"In Progress: {project['in_progress']} | "
                                      f"Overdue: {project['overdue']}"
                        }
                    }],
                    "icon": {"emoji": "📊"}
                }
            }
        ])

        # 添加进度条展示
        progress = int(project['completion_rate'] / 10)
        progress_bar = "🟩" * progress + "⬜" * (10 - progress)
        blocks.append({
            "type": "paragraph",
            "paragraph": {
                "rich_text": [{"text": {"content": f"Progress: {progress_bar}"}}]
            }
        })

    # 创建页面
    return notion.pages.create(
        parent={"page_id": parent_page_id},
        properties={
            "title": {"title": [{"text": {"content": "Project Dashboard"}}]}
        },
        children=blocks
    )

Usage

使用示例

if name == "main": data = generate_project_dashboard( projects_db_id="projects-database-id", tasks_db_id="tasks-database-id" )
print("Project Dashboard")
print("=" * 50)
for project in data:
    print(f"\n{project['project_name']}")
    print(f"  Completion: {project['completion_rate']}%")
    print(f"  Tasks: {project['completed']}/{project['total_tasks']}")
    print(f"  In Progress: {project['in_progress']}")
    print(f"  Overdue: {project['overdue']}")
undefined
if name == "main": data = generate_project_dashboard( projects_db_id="projects-database-id", tasks_db_id="tasks-database-id" )
print("Project Dashboard")
print("=" * 50)
for project in data:
    print(f"\n{project['project_name']}")
    print(f"  Completion: {project['completion_rate']}%")
    print(f"  Tasks: {project['completed']}/{project['total_tasks']}")
    print(f"  In Progress: {project['in_progress']}")
    print(f"  Overdue: {project['overdue']}")
undefined

Integration Examples

集成示例

Integration with Slack

与Slack集成

python
#!/usr/bin/env python3
"""slack_notion.py - Sync Slack messages to Notion"""

import os
import requests
from notion_client import Client

notion = Client(auth=os.environ["NOTION_API_KEY"])
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]

def notify_slack_on_page_update(page_id, message):
    """Send Slack notification when Notion page is updated"""
    page = notion.pages.retrieve(page_id)
    title = page["properties"]["Name"]["title"][0]["plain_text"]

    payload = {
        "blocks": [
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"*Notion Update*: {title}\n{message}"
                }
            },
            {
                "type": "actions",
                "elements": [{
                    "type": "button",
                    "text": {"type": "plain_text", "text": "View in Notion"},
                    "url": page["url"]
                }]
            }
        ]
    }

    requests.post(SLACK_WEBHOOK, json=payload)

def create_notion_page_from_slack(database_id, title, content, channel):
    """Create Notion page from Slack message"""
    return notion.pages.create(
        parent={"database_id": database_id},
        properties={
            "Name": {"title": [{"text": {"content": title}}]},
            "Source": {"select": {"name": "Slack"}},
            "Channel": {"rich_text": [{"text": {"content": channel}}]}
        },
        children=[{
            "type": "paragraph",
            "paragraph": {
                "rich_text": [{"text": {"content": content}}]
            }
        }]
    )
python
#!/usr/bin/env python3
"""slack_notion.py - 将Slack消息同步到Notion"""

import os
import requests
from notion_client import Client

notion = Client(auth=os.environ["NOTION_API_KEY"])
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]

def notify_slack_on_page_update(page_id, message):
    """当Notion页面更新时发送Slack通知"""
    page = notion.pages.retrieve(page_id)
    title = page["properties"]["Name"]["title"][0]["plain_text"]

    payload = {
        "blocks": [
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"*Notion Update*: {title}\n{message}"
                }
            },
            {
                "type": "actions",
                "elements": [{
                    "type": "button",
                    "text": {"type": "plain_text", "text": "View in Notion"},
                    "url": page["url"]
                }]
            }
        ]
    }

    requests.post(SLACK_WEBHOOK, json=payload)

def create_notion_page_from_slack(database_id, title, content, channel):
    """从Slack消息创建Notion页面"""
    return notion.pages.create(
        parent={"database_id": database_id},
        properties={
            "Name": {"title": [{"text": {"content": title}}]},
            "Source": {"select": {"name": "Slack"}},
            "Channel": {"rich_text": [{"text": {"content": channel}}]}
        },
        children=[{
            "type": "paragraph",
            "paragraph": {
                "rich_text": [{"text": {"content": content}}]
            }
        }]
    )

Integration with GitHub

与GitHub集成

python
#!/usr/bin/env python3
"""github_notion.py - Sync GitHub issues to Notion"""

import os
import requests
from notion_client import Client

notion = Client(auth=os.environ["NOTION_API_KEY"])
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]

def sync_github_issues_to_notion(repo, database_id):
    """Sync GitHub issues to Notion database"""
    # Fetch issues from GitHub
    response = requests.get(
        f"https://api.github.com/repos/{repo}/issues",
        headers={"Authorization": f"token {GITHUB_TOKEN}"}
    )
    issues = response.json()

    for issue in issues:
        # Check if issue already exists in Notion
        existing = notion.databases.query(
            database_id=database_id,
            filter={
                "property": "GitHub ID",
                "number": {"equals": issue["number"]}
            }
        )

        properties = {
            "Name": {"title": [{"text": {"content": issue["title"]}}]},
            "GitHub ID": {"number": issue["number"]},
            "Status": {
                "select": {"name": "Open" if issue["state"] == "open" else "Closed"}
            },
            "URL": {"url": issue["html_url"]},
            "Labels": {
                "multi_select": [{"name": l["name"]} for l in issue["labels"]]
            }
        }

        if existing["results"]:
            # Update existing
            notion.pages.update(
                page_id=existing["results"][0]["id"],
                properties=properties
            )
        else:
            # Create new
            notion.pages.create(
                parent={"database_id": database_id},
                properties=properties,
                children=[{
                    "type": "paragraph",
                    "paragraph": {
                        "rich_text": [{"text": {"content": issue.get("body", "") or ""}}]
                    }
                }]
            )

    print(f"Synced {len(issues)} issues from {repo}")
python
#!/usr/bin/env python3
"""github_notion.py - 将GitHub Issues同步到Notion"""

import os
import requests
from notion_client import Client

notion = Client(auth=os.environ["NOTION_API_KEY"])
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]

def sync_github_issues_to_notion(repo, database_id):
    """将GitHub Issues同步到Notion数据库"""
    # 从GitHub获取Issues
    response = requests.get(
        f"https://api.github.com/repos/{repo}/issues",
        headers={"Authorization": f"token {GITHUB_TOKEN}"}
    )
    issues = response.json()

    for issue in issues:
        # 检查Issue是否已存在于Notion
        existing = notion.databases.query(
            database_id=database_id,
            filter={
                "property": "GitHub ID",
                "number": {"equals": issue["number"]}
            }
        )

        properties = {
            "Name": {"title": [{"text": {"content": issue["title"]}}]},
            "GitHub ID": {"number": issue["number"]},
            "Status": {
                "select": {"name": "Open" if issue["state"] == "open" else "Closed"}
            },
            "URL": {"url": issue["html_url"]},
            "Labels": {
                "multi_select": [{"name": l["name"]} for l in issue["labels"]]
            }
        }

        if existing["results"]:
            # 更新现有条目
            notion.pages.update(
                page_id=existing["results"][0]["id"],
                properties=properties
            )
        else:
            # 创建新条目
            notion.pages.create(
                parent={"database_id": database_id},
                properties=properties,
                children=[{
                    "type": "paragraph",
                    "paragraph": {
                        "rich_text": [{"text": {"content": issue.get("body", "") or ""}}]
                    }
                }]
            )

    print(f"Synced {len(issues)} issues from {repo}")

Best Practices

最佳实践

1. Rate Limiting

1. 速率限制

python
import time
from functools import wraps

def rate_limit(calls_per_second=3):
    """Decorator to rate limit API calls"""
    min_interval = 1.0 / calls_per_second
    last_called = [0.0]

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            elapsed = time.time() - last_called[0]
            wait_time = min_interval - elapsed
            if wait_time > 0:
                time.sleep(wait_time)
            result = func(*args, **kwargs)
            last_called[0] = time.time()
            return result
        return wrapper
    return decorator
python
import time
from functools import wraps

def rate_limit(calls_per_second=3):
    """用于限制API调用速率的装饰器"""
    min_interval = 1.0 / calls_per_second
    last_called = [0.0]

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            elapsed = time.time() - last_called[0]
            wait_time = min_interval - elapsed
            if wait_time > 0:
                time.sleep(wait_time)
            result = func(*args, **kwargs)
            last_called[0] = time.time()
            return result
        return wrapper
    return decorator

Usage

使用示例

@rate_limit(calls_per_second=3) def api_call(func, *args, **kwargs): return func(*args, **kwargs)
undefined
@rate_limit(calls_per_second=3) def api_call(func, *args, **kwargs): return func(*args, **kwargs)
undefined

2. Error Handling

2. 错误处理

python
from notion_client import APIResponseError

def safe_notion_call(func, *args, max_retries=3, **kwargs):
    """Execute Notion API call with retry logic"""
    for attempt in range(max_retries):
        try:
            return func(*args, **kwargs)
        except APIResponseError as e:
            if e.status == 429:
                # Rate limited
                wait_time = int(e.headers.get("Retry-After", 60))
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
            elif e.status >= 500:
                # Server error, retry
                time.sleep(2 ** attempt)
            else:
                raise
        except Exception as e:
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)
            else:
                raise

    raise Exception(f"Failed after {max_retries} retries")
python
from notion_client import APIResponseError

def safe_notion_call(func, *args, max_retries=3, **kwargs):
    """带重试逻辑的Notion API调用执行函数"""
    for attempt in range(max_retries):
        try:
            return func(*args, **kwargs)
        except APIResponseError as e:
            if e.status == 429:
                # 速率限制
                wait_time = int(e.headers.get("Retry-After", 60))
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
            elif e.status >= 500:
                # 服务器错误,重试
                time.sleep(2 ** attempt)
            else:
                raise
        except Exception as e:
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)
            else:
                raise

    raise Exception(f"Failed after {max_retries} retries")

3. Batch Operations

3. 批量操作

python
def batch_create_pages(database_id, pages_data, batch_size=10):
    """Create pages in batches to avoid rate limits"""
    results = []
    for i in range(0, len(pages_data), batch_size):
        batch = pages_data[i:i + batch_size]
        for page_data in batch:
            result = notion.pages.create(
                parent={"database_id": database_id},
                properties=page_data["properties"],
                children=page_data.get("children", [])
            )
            results.append(result)
        if i + batch_size < len(pages_data):
            time.sleep(1)  # Brief pause between batches
    return results
python
def batch_create_pages(database_id, pages_data, batch_size=10):
    """批量创建页面以避免速率限制"""
    results = []
    for i in range(0, len(pages_data), batch_size):
        batch = pages_data[i:i + batch_size]
        for page_data in batch:
            result = notion.pages.create(
                parent={"database_id": database_id},
                properties=page_data["properties"],
                children=page_data.get("children", [])
            )
            results.append(result)
        if i + batch_size < len(pages_data):
            time.sleep(1)  # 批次间短暂暂停
    return results

4. Caching

4. 缓存

python
import json
from pathlib import Path
from datetime import datetime, timedelta

CACHE_DIR = Path.home() / ".cache" / "notion"
CACHE_TTL = timedelta(minutes=5)

def get_cached_or_fetch(key, fetch_func, ttl=CACHE_TTL):
    """Get from cache or fetch fresh data"""
    CACHE_DIR.mkdir(parents=True, exist_ok=True)
    cache_file = CACHE_DIR / f"{key}.json"

    if cache_file.exists():
        data = json.loads(cache_file.read_text())
        cached_at = datetime.fromisoformat(data["cached_at"])
        if datetime.now() - cached_at < ttl:
            return data["value"]

    value = fetch_func()
    cache_data = {
        "cached_at": datetime.now().isoformat(),
        "value": value
    }
    cache_file.write_text(json.dumps(cache_data, default=str))
    return value
python
import json
from pathlib import Path
from datetime import datetime, timedelta

CACHE_DIR = Path.home() / ".cache" / "notion"
CACHE_TTL = timedelta(minutes=5)

def get_cached_or_fetch(key, fetch_func, ttl=CACHE_TTL):
    """从缓存获取或获取新鲜数据"""
    CACHE_DIR.mkdir(parents=True, exist_ok=True)
    cache_file = CACHE_DIR / f"{key}.json"

    if cache_file.exists():
        data = json.loads(cache_file.read_text())
        cached_at = datetime.fromisoformat(data["cached_at"])
        if datetime.now() - cached_at < ttl:
            return data["value"]

    value = fetch_func()
    cache_data = {
        "cached_at": datetime.now().isoformat(),
        "value": value
    }
    cache_file.write_text(json.dumps(cache_data, default=str))
    return value

Troubleshooting

故障排除

Common Issues

常见问题

Issue: 401 Unauthorized
python
undefined
问题:401 Unauthorized
python
undefined

Verify API key

验证API密钥

curl -s "https://api.notion.com/v1/users/me"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
curl -s "https://api.notion.com/v1/users/me"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"

Check if integration is connected to the page/database

检查集成是否已连接到页面/数据库

Go to page > ... menu > Connections > Your integration

进入页面 > ...菜单 > Connections > 选择你的集成


**Issue: 404 Not Found**
```python

**问题:404 Not Found**
```python

Ensure integration has access to the page

确保集成有权访问该页面

The integration must be explicitly connected to each page

集成必须显式连接到每个页面

For databases, check the database ID is correct

对于数据库,检查数据库ID是否正确

Database ID format: 32 hex characters (with or without hyphens)

数据库ID格式:32个十六进制字符(可带或不带连字符)


**Issue: 400 Bad Request**
```python

**问题:400 Bad Request**
```python

Check property names match exactly (case-sensitive)

检查属性名称是否完全匹配(区分大小写)

Verify property types match the database schema

验证属性类型是否与数据库架构匹配

Common mistakes:

常见错误:

- Using "title" instead of actual title property name

- 使用"title"而非实际的标题属性名称

- Wrong select/multi_select option names

- 单选/多选选项名称错误

- Invalid date format (use ISO 8601: "2025-01-17")

- 日期格式无效(使用ISO 8601格式:"2025-01-17")


**Issue: Rate limiting (429)**
```python

**问题:速率限制(429)**
```python

Notion allows ~3 requests/second

Notion允许约3次请求/秒

Implement exponential backoff

实现指数退避策略

Check Retry-After header for wait time

检查Retry-After头获取等待时间

undefined
undefined

Version History

版本历史

VersionDateChanges
1.0.02025-01-17Initial release with comprehensive Notion API coverage
版本日期变更
1.0.02025-01-17初始版本,全面覆盖Notion API

Resources

资源


This skill enables powerful workspace automation through Notion's comprehensive API, supporting databases, pages, blocks, queries, and integration patterns.

本技能通过Notion的全面API实现强大的工作区自动化,支持数据库、页面、块、查询及集成模式。