飞书 API 2-4:如何使用 API 将数据写入数据表

一、引入

上一篇创建好数据表之后,接下来就是写入数据和对数据的处理。

本文主要探讨数据的插入、更新和删除操作。所有的操作都是基于上一篇(飞书 API 2-4)创建的数据表进行操作。上面最终的数据表只有 2 个字段:序号和邮箱。
序号是多维表自动填充的自增数字,所以我们处理的时候不需要处理该字段,只需要处理邮箱即可。

二、数据操作

2.1 插入数据

2.1.1 插入单条记录

💡API 文档:新增记录
插入数据也需要指定“app_token”和“table_id”,除了这两个必要参数只要,还需要提供带有字段数据的请求体。比如我要插入张三的邮箱,示例如下:

{
  "fields": {
    "邮箱": "zhangsan@qq.com"
  }
}

在 API 调试台选择新增记录 API 输入“app_token”、“table_id”和请求体调试一下,从响应体可以看到插入数据成功(code=0),还返回了数据的“record_id”(用于更新数据记录):
image.png

查看多维表,可以看到多了一条记录,记录张三的邮箱信息。
image.png

2.1.2 插入多条记录

如果我要插入多条数据呢?该怎么办?飞书官方提供了插入多条记录的接口。
💡API 文档:新增多条记录
插入多条记录的数据结构相比单条记录多了一层“records”,即:{“records”:[<记录1>,<记录2>]}。
举个例子,我要新增李四、王五的邮箱,请求体示例如下:

{
    "records": [
        {
            "fields": {
                "邮箱": "lisi@qq.dom"
            }
        },
        {
            "fields": {
                "邮箱": "wangwu@qq.dom"
            }
        }
    ]
}

在 API 调试台选择新增记录 API 输入“app_token”、“table_id”和请求体进行调试,结果如下,成功插入了 2 条记录。
image.png

查看多维表,可以看到多了2条记录,分别记录李四、王五的邮箱信息。
image.png

2.2 更新数据

💡API 文档:更新记录更新多条记录
更新数据同样也有 2 个 API,一个更新单条记录,一个更新多条记录。
分两个案例来展开:

  • 【案例1】将第一条记录张三的邮箱改为赵六的邮箱;
  • 【案例2】将第二、三的邮箱后缀的 dom 纠正为 com。

“app_token”和“table_id”同插入数据,下面主要展开其他的参数和请求体。

2.2.1 更新单条记录

【案例1】使用更新单条记录来实现,该接口需要额外传递一个“record_id”参数和带更新后数据的请求体。

  • 前面新增张三记录的时候,从响应体可以看到“record_id”为“recugpFE98VUrz”。
  • 请求体参考如下,结构和插入单条数据一样。
{
  "fields": {
    "邮箱": "zhaoliu@qq.com"
  }
}

查看调试结果(如下),执行成功。
image.png

查看多维表记录,已将“zhangsan@qq.com”改为“zhaoliu@qq.com”。
image.png

2.2.2 更新多条记录

【案例2】使用更新多条记录的接口来实现。
接口的结构和新增记录的结构类似,比更新单条记录多了一层“records”,不同点在于,更新记录需要知道“record_id”,所以在和“fields”同级的字典,多了一个“record_id”的键值对。
基本结构:{“records”:[<记录1>,<记录2>]}(和新增记录类型),再下一层:{“records”:[{<record_id键值对>,<fields键值对>},{<record_id键值对>,<fields键值对>}]}。
另外,相比更新单条记录,更新多条记录,不用额外传递“record_id”参数,直接通过请求体传递该值。

{
    "records": [
        {
            "record_id": "recugpJxfd7jpK",
            "fields": {
                "邮箱": "lisi@qq.com"
            }
        },
        {
            "record_id": "recugpJxfdexmw",
            "fields": {
                "邮箱": "wangwu@qq.com"
            }
        }
    ]
}

调试结果如下,执行成功。
image.png

查看多维表记录,已将“dom”改为“com”。
image.png

其实无论是单条记录还是多条记录的更新,都可以使用多条记录来实现。

2.3 删除数据

💡API 文档:删除记录删除多条记录
删除数据同样也有 2 个 API,一个删除单条记录,一个删除多条记录。相对更新数据来说,删除数据就简单了。
只需要传递“record_id”即可。
删除单条记录,传递“record_id”参数,如删除数据表的第一条记录,如下图,传递三个参数发起调试即可删除序号为 1 的记录。
image.png

删除多条记录,在请求体传递“record_id”的值,放在列表即可,不需要使用键值对。如删除第2、3条记录,将它们的“record_id”放到列表中,如下:

{
    "records": [
        "recugpJxfd7jpK",
        "recugpJxfdexmw"
    ]
}

然后到 API 调试台发起调试,如下图,调试成功之后,便把序号为 2 和 3 的记录删除。
image.png

2.4 不同字段类型的数据示例

从上文,其实可以发现,飞书的数据的插入和更新,都是基于字段名称的,通过字段名称对字段的值进行插入和更新。
支持通过 API 写入数据的字段类型如下:

  • “type”类型支持:1、2、3、4、5、7、11、13、15、17、18、21、22、23。
  • “ui_type”类型支持:Text、Barcode、Email、Number、Progress、Currency、Rating、SingleSelect、MultiSelect、DateTime、Checkbox、User、GroupChat、Phone、Url、Attachment、SingleLink、DuplexLink、Location。

换个说法,不支持以下 4 种字段类型通过 API 创建:查找引用、公式、流程、创建时间、最后更新时间、创建人、修改人、自动编号、按钮。除了流程和按钮,其他的都有一个特征,就是会自动更新,配置好之后不需要人工维护。

不同的字段类型,要求传递的数据格式有所差异。以下是使用新增多条记录的 API 的请求体的参考示例:

{
  "records": [
    {
      "fields": {
        "多行文本": "文本",
        "条码": "978-7-111-48565-0",
        "email": "lisi@qq.com",
        "数字": 100,
        "货币": 3,
        "评分": 3,
        "进度": 0.25,
        "单选": "选项2",
        "多选": [
          "选项1",
          "选项4"
        ],
        "日期": 1677206443000,
        "复选框": true,
        "人员": [
          {
            "id": "ou_4007a8a82cc6e0874524edda12ce94b1"
          }
        ],
        "群组": [
          {
            "id": "oc_4db36e6b4ef56960cae2544ec9ae519c"
          }
        ],
        "电话号码": "13026162666",
        "超链接": {
          "text": "飞书多维表格官网",
          "link": "https://www.feishu.cn/product/base"
        },
        "附件": [
          {
            "file_token": "DRiFbwaKsoZaLax4WKZbEGCccoe"
          },
          {
            "file_token": "BZk3bL1Enoy4pzxaPL9bNeKqcLe"
          }
        ],
        "单向关联": [
          "recugudw7J76ql"
        ],
        "双向关联": [
          "recugudw7J76ql",
          "recugudugm9af0"
        ],
        "地理位置": "116.397755,39.903179"
      }
    }
  ]
}

根据数据结构和类型可以分为六类:

  • 字符串:多行文本、条码、单选、电话号码、地理位置,其中,地理位置需要经纬度
  • 数字:数字、进度、货币、评分、日期,其中,日期是一个时间戳
  • 布尔值:复选框
  • 字典:超链接,需要链接名和链接
  • 列表:多选、单向关联、双向关联,其中,单向关联和双向关联必须是其他数据表的“record_id”
  • 列表嵌套字典:人员、群组、附件,其中,人员需要传递用户ID,群组需要传递群组ID,附件需要文件上传到飞书多维表之后的文件 token。
    • 需要特别注意的时,写入群组ID必须有相关的权限,比如说在群体添加应用机器人,否则会报错:“An invalid or unauthorized ‘GroupChat’ id oc_xxx can’t be provided. ”。

相对于读取而言,写入的内容比较难以统一代码,因为读取的源是飞书多维表,数据格式是固定的,但是写入的源数据格式是未知的,比如同样是字符串,地理位置写入必须是一个通过英文逗号分隔的经纬度,才能最终识别为具体的位置,但是数据的来源是不确定的,可能是一个地名。
所以最好的情况是在读取数据源之后,直接进行处理,将源数据处理为和飞书多维表要求的数据结构一致的数据,直接写入多维表。

在实践的过程中,用的比较多的通常是:文本、单选、数字、日期等类型,遇到比较多的处理通常是将数据源的日期转为毫秒的时间戳,然后插入数据。

三、小结

本文探讨了如何通过 API 操作多维表数据的新增、更新和删除:

  • 新增记录:需要“app_token”、“table_id”和字段及字段值;
  • 更新记录:需要“app_token”、“table_id”、“record_id”和字段及新的字段值;
  • 删除记录:需要“app_token”、“table_id”和“record_id”。

同时梳理了 28 种字段类型是否支持 API 写入及支持写入的字段类型的相关数据结构:

序号 type ui_type 中文描述 API 支持 数据结构示例
1 1 Text 多行文本 支持 “文本”
2 1 Barcode 条码 支持 “978-7-111-48565-0”
3 1 Email 邮箱 支持 “lisi@qq.com”
4 2 Number 数字 支持 100
5 2 Progress 进度 支持 3
6 2 Currency 货币 支持 3
7 2 Rating 评分 支持 0.25
8 3 SingleSelect 单选 支持 “选项1”
9 4 MultiSelect 多选 支持 [“选项1”,“选项2”]
10 5 DateTime 日期 支持 1704038400000
11 7 Checkbox 复选框 支持 true/false
12 11 User 人员 支持 [{“id”:“ou_xxx”}]
13 13 Phone 电话号码 支持 “135xxx”
14 15 Url 超链接 支持 {“text”:“名称”,“link”:“https:xxx”}
15 17 Attachment 附件 支持 [{“file_token”:“xxx”}]
16 18 SingleLink 单向关联 支持 [“recuxxx”,“recuxxx”]
17 19 Lookup 查找引用 不支持
18 20 Formula 公式 不支持
19 21 DuplexLink 双向关联 支持 [“recuxxx”,“recuxxx”]
20 22 Location 地理位置 支持 “116.39775,39.903179”
21 23 GroupChat 群组 支持 [{“id”:“oc_xxx”}]
22 24 Stage 流程 不支持
23 1001 CreatedTime 创建时间 不支持
24 1002 ModifiedTime 最后更新时间 不支持
25 1003 CreatedUser 创建人 不支持
26 1004 ModifiedUser 修改人 不支持
27 1005 AutoNumber 自动编号 不支持
28 3001 Button 按钮 不支持

附录:代码小结

# 由于单条记录也可以通过多条记录的接口实现,本代码仅展示多条记录的接口。

import requests
import json

def insert_records(access_token,app_token,table_id,request_body):
    url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_create"
    
    payload = json.dumps(request_body)
    
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {access_token}'
    }

    response = requests.request("POST", url, headers=headers, data=payload)
    code = response.json()['code']
    if code == 0:
        len_record = len(request_body["records"])
        print(f"成功插入 {len_record} 数据。关联函数:insert_records。")
    else:
        msg = response.json().get("msg")
        raise f"插入数据失败,失败信息:{msg}。关联函数:insert_records。"


def update_records(access_token,app_token,table_id,request_body):
    url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_update"
    payload = json.dumps(request_body)

    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {access_token}'
    }

    response = requests.request("POST", url, headers=headers, data=payload)
    code = response.json()['code']
    if code == 0:
        len_record = len(request_body["records"])
        print(f"成功更新 {len_record} 数据。关联函数:update_records。")
    else:
        msg = response.json().get("msg")
        raise f"更新数据失败,失败信息:{msg}。关联函数:update_records。"

def delete_records(access_token,app_token,table_id,request_body):
    url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_delete"
    payload = json.dumps(request_body)

    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {access_token}'
    }

    response = requests.request("POST", url, headers=headers, data=payload)
    code = response.json()['code']
    if code == 0:
        len_record = len(request_body["records"])
        print(f"成功删除 {len_record} 数据。关联函数:delete_records。")
    else:
        msg = response.json().get("msg")
        raise f"更新数据失败,失败信息:{msg}。关联函数:delete_records。"

def get_tenant_access_token(app_id, app_secret):
    url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
    payload = json.dumps({
        "app_id": app_id,
        "app_secret": app_secret
    })
    headers = {'Content-Type': 'application/json'}
    response = requests.request("POST", url, headers=headers, data=payload)
    tenant_access_token = response.json()['tenant_access_token']
    print(f'成功获取tenant_access_token:{tenant_access_token}。关联函数:get_table_params。')
    return tenant_access_token


def main(request_body):
    app_id = 'your_app_id'
    app_secret = 'your_app_secret'
    app_token = 'your_app_token'
    table_id = 'your_table_id'
    access_token = get_tenant_access_token(app_id, app_secret)

    # 插入数据
    request_body = {
        "records": [
            {
                "fields": {
                    "邮箱": "lisi@qq.dom"
                }
            },
            {
                "fields": {
                    "邮箱": "wangwu@qq.dom"
                }
            }
        ]
    }
    insert_records(access_token,app_token,table_id,request_body)
    
    # 更新数据
    request_body = {
    	"records": [
    		{
    			"fields": {
    				"邮箱": "lisi@qq.com"
    			},
    			"record_id": "your_record_id"
    		},
    		{
    			"fields": {
    				"邮箱": "wangwu@qq.com"
    			},
    			"record_id": "your_record_id"
    		}
    	]
    }
    update_records(access_token,app_token,table_id,request_body)

    # 删除数据
    request_body = {
    	"records": [
    		"your_record_id",
    		"your_record_id"
    	]
    }
    delete_records(access_token,app_token,table_id,request_body)

    
if __name__ == '__main__':    
    main()

相关推荐

  1. 【C语言】如何数据写入文件?

    2024-07-10 10:56:03       27 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 10:56:03       4 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 10:56:03       5 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 10:56:03       4 阅读
  4. Python语言-面向对象

    2024-07-10 10:56:03       4 阅读

热门阅读

  1. Perl 语言入门学习

    2024-07-10 10:56:03       9 阅读
  2. 大模型/NLP/算法面试题总结3——BERT和T5的区别?

    2024-07-10 10:56:03       15 阅读
  3. 单元测试核心类备忘

    2024-07-10 10:56:03       10 阅读
  4. Node.js有什么优点

    2024-07-10 10:56:03       10 阅读
  5. Python爬虫-获取懂车帝“指定车型”的销量数据

    2024-07-10 10:56:03       9 阅读
  6. 深入解析CSS中的!important规则:优先级与最佳实践

    2024-07-10 10:56:03       10 阅读
  7. Django中模型的基于类的混入

    2024-07-10 10:56:03       9 阅读