notion-api
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNotion 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 childrenmarkdown
1. 打开要访问的Notion页面/数据库
2. 点击右上角的「...」菜单
3. 点击「Connections」>「Connect to」> 选择你的集成
4. 集成现在可以访问此页面及其子页面Environment Setup
环境设置
bash
undefinedbash
undefinedSet 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
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28" | jq
undefinedcurl -s "https://api.notion.com/v1/users/me"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28" | jq
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28" | jq
undefinedPython SDK Installation
Python SDK安装
bash
undefinedbash
undefinedInstall 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
undefinedpip install python-dotenv requests
undefinedVerify 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")
undefineddatabases = notion.search(filter={"property": "object", "value": "database"})
print(f"Found {len(databases['results'])} databases")
undefinedCore Capabilities
核心功能
1. Database Operations
1. 数据库操作
List and Search Databases:
bash
undefined列出并搜索数据库:
bash
undefinedSearch 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}'
-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}'
-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'
-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'
-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": {}}
}
)
undefinednotion.databases.update(
database_id="your-database-id",
title=[{"type": "text", "text": {"content": "Updated Title"}}],
properties={
"New Property": {"rich_text": {}}
}
)
undefined2. Query Databases
2. 查询数据库
Basic Query:
bash
undefined基础查询:
bash
undefinedQuery 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'
-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'
-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'
-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'
-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'
-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:**
```pythoncurl -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'
-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 - 查询操作:**
```pythonSimple 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_resultsall_items = query_all_pages("your-database-id")
print(f"Total items: {len(all_items)}")
undefineddef 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_resultsall_items = query_all_pages("your-database-id")
print(f"Total items: {len(all_items)}")
undefined3. Filter Syntax Reference
3. 过滤器语法参考
Text Filters:
python
undefined文本过滤器:
python
undefinedText 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": {}}}
**单选/多选过滤器:**
```pythonSelect
单选
{"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
undefinedRelation
关联
{"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}}}
**复合过滤器:**
```pythonAND
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"}}
]
}
undefined4. Page Operations
4. 页面操作
Create Pages:
bash
undefined创建页面:
bash
undefinedCreate 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
-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:**
```pythoncurl -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
-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 - 页面操作:**
```pythonCreate 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
)
undefinednotion.pages.update(
page_id="page-id",
archived=False
)
undefined5. Block Operations
5. 块操作
Block Types:
python
undefined块类型:
python
undefinedParagraph
段落
{
"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 - 块操作:**
```pythonGet 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_blocksall_blocks = get_all_blocks("page-id")
print(f"Total blocks: {len(all_blocks)}")
undefineddef 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_blocksall_blocks = get_all_blocks("page-id")
print(f"Total blocks: {len(all_blocks)}")
undefined6. Rich Text Formatting
6. 富文本格式化
Rich Text Structure:
python
undefined富文本结构:
python
undefinedBasic 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 rtUsage
使用示例
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}
}]
)
undefinedparagraph_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}
}]
)
undefined7. Relations and Rollups
7. 关联与汇总
Create Related Databases:
python
undefined创建关联数据库:
python
undefinedCreate 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"}]}
}
)
undefinednotion.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"}]}
}
)
undefined8. Search API
8. 搜索API
Search Operations:
python
undefined搜索操作:
python
undefinedSearch 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_resultsundefineddef 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_resultsundefinedComplete 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']}")undefinedif 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']}")undefinedExample 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 resultpython
#!/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 resultUsage
使用示例
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)undefinedif 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)undefinedExample 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']}")undefinedif 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']}")undefinedIntegration 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 decoratorpython
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 decoratorUsage
使用示例
@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)
undefined2. 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 resultspython
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 results4. 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 valuepython
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 valueTroubleshooting
故障排除
Common Issues
常见问题
Issue: 401 Unauthorized
python
undefined问题:401 Unauthorized
python
undefinedVerify API key
验证API密钥
curl -s "https://api.notion.com/v1/users/me"
-H "Authorization: Bearer $NOTION_API_KEY"
-H "Notion-Version: 2022-06-28"
-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"
-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**
```pythonEnsure 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**
```pythonCheck 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)**
```pythonNotion allows ~3 requests/second
Notion允许约3次请求/秒
Implement exponential backoff
实现指数退避策略
Check Retry-After header for wait time
检查Retry-After头获取等待时间
undefinedundefinedVersion History
版本历史
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2025-01-17 | Initial release with comprehensive Notion API coverage |
| 版本 | 日期 | 变更 |
|---|---|---|
| 1.0.0 | 2025-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实现强大的工作区自动化,支持数据库、页面、块、查询及集成模式。