飞书配置表数据同步到数据库中

发布于:2025-05-13 ⋅ 阅读:(7) ⋅ 点赞:(0)

这是我的从飞书取数据的代码

def get_employee_from_feishu():
    staff_setting  = settings.FEISHU_SETTING["sales_order"]["employee"]
    app_token = staff_setting ["app_token"]
    table_id = staff_setting ["table_id"]

    page_token = None
    hasMore = True
    employees = {}

    while hasMore:
        staff_data = bitable_service.fetch(app_token, table_id, page_token=page_token)
        # 格式参考warehouse.json
        hasMore = staff_data["data"]["has_more"]
        rows = staff_data["data"]["items"]

        for row in rows:
            fields = row["fields"]
            if "姓名" in fields:
                employee = {
                    "employee_id": fields.get("工号"),
                    "name": fields.get("姓名"),
                    "position": fields.get("人员.职务"),
                    "department": fields.get("部门名"),
                }
                employees[employee["name"]] = employee

        if not hasMore:
            break
        page_token = staff_data["data"].get("page_token")

    return employees

这是我的数据库模型

from django.db import models


class EmployeeModel(models.Model):
    employee_id = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name="工号")
    name = models.CharField(max_length=64, null=True, blank=True, verbose_name="姓名")
    position = models.CharField(max_length=100, null=True, blank=True, verbose_name="人员.职务")
    department = models.CharField(max_length=100, null=True, blank=True, verbose_name="部门名")

    class Meta:
        db_table = "xss_employee"
        verbose_name = "员工信息"
        verbose_name_plural = "员工信息"

    def __str__(self):
        return self.name

这是我将飞书数据进入数据库的代码

from core.models import EmployeeModel
from eccang.services.base_data_fetch_service import (
    get_product_category_from_feishu,
    get_warehouse_from_feishu,
    get_employee_from_feishu,
    get_country_from_feishu,
    get_monthly_target_from_feishu,
    get_position_target_from_feishu,
)



def sync_employee_to_db():
    data_dict = get_employee_from_feishu()
    for data in data_dict.values():
        if not data["employee_id"]:
            continue  # 跳过无工号数据

        EmployeeModel.objects.update_or_create(
            employee_id=data["employee_id"],
            defaults={
                "name": data["name"],
                "position": data["position"],
                "department": data["department"],
            }
        )

✅不错的地方

使用分页抓取飞书数据,防止数据量大时漏数据。

使用 update_or_create,避免重复插入。

过滤掉没有 employee_id 的记录,防止插入空主键。

🔍建议优化点

  1. 字段容错性检查
    在访问字段时使用了 fields.get(),但在 position、department、employee_id 字段不是所有记录都存在时,可能得到 None。可以在构建 employee 字典时加默认值,避免报错或数据不一致:
employee = {
    "employee_id": fields.get("工号", "").strip(),
    "name": fields.get("姓名", "").strip(),
    "position": fields.get("人员.职务", "").strip(),
    "department": fields.get("部门名", "").strip(),
}

注意 .strip() 可避免导入数据库中的空格异常。

  1. 避免空姓名造成 key 重复覆盖
    使用了 employees[employee[“name”]] = employee,这会以“姓名”作为 key,而如果出现多个同名员工,可能被覆盖,造成数据丢失。

建议改为用 employee_id 做 key,更稳妥:

employees[employee["employee_id"]] = employee
  1. 字段命名检查
    使用的是字段名如 “人员.职务”,这是合法的,但建议在飞书中避免这种带点的字段名,因为它可能与 Python 字段语义混淆,或者将来你要做统一映射时会麻烦。

  2. 同步逻辑建议加日志(可选)
    可以加一点日志输出,方便调试或上线监控:

import logging
logger = logging.getLogger(__name__)

def sync_employee_to_db():
    data_dict = get_employee_from_feishu()
    created, updated, skipped = 0, 0, 0

    for data in data_dict.values():
        if not data["employee_id"]:
            skipped += 1
            continue

        obj, is_created = EmployeeModel.objects.update_or_create(
            employee_id=data["employee_id"],
            defaults={
                "name": data["name"],
                "position": data["position"],
                "department": data["department"],
            }
        )
        if is_created:
            created += 1
        else:
            updated += 1

    logger.info(f"员工同步完成:新增 {created} 条,更新 {updated} 条,跳过 {skipped} 条")

✅ 总结

飞书分页抓取

空值处理
⚠️ 建议加默认值 .get(…, “”).strip()
主键唯一性
⚠️ 建议用 employee_id 做 key
数据同步方式
✅ update_or_create 正确
日志与监控
⚠️ 建议加简单日志
字段命名规范性
⚠️ “人员.职务” 命名不够语义清晰,建议优化

下面是这段同步员工数据代码的详细结构分析,包括每一部分的职责、依赖关系、潜在问题和优化建议。

一、函数入口:sync_employee_to_db()

def sync_employee_to_db():

作用:
主函数,负责执行“从飞书多维表格获取员工数据 → 写入本地数据库”的全过程。

二、从飞书获取数据

data_dict = get_employee_from_feishu()

对应的函数:

def get_employee_from_feishu():
    staff_setting  = settings.FEISHU_SETTING["sales_order"]["employee"]
    app_token = staff_setting ["app_token"]
    table_id = staff_setting ["table_id"]

    page_token = None
    hasMore = True
    employees = {}

    while hasMore:
        staff_data = bitable_service.fetch(app_token, table_id, page_token=page_token)
        hasMore = staff_data["data"]["has_more"]
        rows = staff_data["data"]["items"]

        for row in rows:
            fields = row["fields"]
            if "姓名" in fields:
                employee = {
                    "employee_id": fields.get("工号"),
                    "name": fields.get("姓名"),
                    "position": fields.get("人员.职务"),
                    "department": fields.get("部门名"),
                }
                employees[employee["name"]] = employee

        if not hasMore:
            break
        page_token = staff_data["data"].get("page_token")

    return employees

作用:
调用 bitable_service.fetch() 与飞书 API 通信;
按页遍历所有员工数据;
将每条员工记录解析为字典格式;
最后以 “姓名” 为 key 构造一个员工字典并返回。

依赖项:
bitable_service.fetch():对飞书多维表格的 API 封装;
settings.FEISHU_SETTING:飞书的 App Token 和表格 ID 来自配置文件;
字段名称如 “工号”, “姓名”, “人员.职务” 是 Feishu 表格中的字段。

潜在问题:
employees[employee[“name”]] = employee:若员工同名会被覆盖;
若某行 fields 缺少必要字段,可能插入 None;
没有 .strip() 清洗字符串,可能出现数据不一致(如 "张三 " vs “张三”);
若飞书接口失败,未处理异常(建议加 try-except);

三、同步到数据库

for data in data_dict.values():
    if not data["employee_id"]:
        continue  # 跳过无工号数据

    EmployeeModel.objects.update_or_create(
        employee_id=data["employee_id"],
        defaults={
            "name": data["name"],
            "position": data["position"],
            "department": data["department"],
        }
    )

作用:
遍历每条员工数据;
以 “employee_id” 作为唯一键更新或插入 EmployeeModel;
若数据库中已存在对应 employee_id,则更新其他字段;
若不存在,则创建新记录。

优点:
update_or_create 可以自动处理“增”和“改”,逻辑清晰;
使用 “employee_id” 作为唯一键,符合业务设计;

建议优化:
增加日志记录,比如:新增了多少条、更新了多少条;
对于姓名为空或异常的数据可以加校验;
加异常处理,防止单条数据出错影响整个同步流程。

四、模型结构分析:EmployeeModel

class EmployeeModel(models.Model):
    employee_id = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name="工号")
    name = models.CharField(max_length=64, null=True, blank=True, verbose_name="姓名")
    position = models.CharField(max_length=100, null=True, blank=True, verbose_name="人员.职务")
    department = models.CharField(max_length=100, null=True, blank=True, verbose_name="部门名")

    class Meta:
        db_table = "xss_employee"
        verbose_name = "员工信息"
        verbose_name_plural = "员工信息"

    def __str__(self):
        return self.name

字段解释:
字段名 类型 含义
employee_id CharField 员工工号,设为唯一键
name CharField 员工姓名
position CharField 职位/职务
department CharField 部门名称

建议:
如果业务上“工号”不可能为空,可以设置 null=False, blank=False;
添加 created_at、updated_at 字段,用于数据变更追踪;
可对 name 加索引提升查询效率(如果经常用 name 查询)。

五、完整建议汇总

数据来源字段容错 .get(“字段”, “”).strip(),避免出现空值和空格
唯一键选择 不建议用 name 做 dict key,推荐用 employee_id
字段覆盖 如果同名员工存在,当前写法会覆盖后者数据,应避免
接口容错 加 try-except 捕获 Feishu API 错误
数据变更记录 加入 日志记录(如新增几条,更新几条)
模型增强 建议增加时间戳字段(created_at, updated_at)
配置来源 建议统一放到 settings,例如字段映射配置等,便于维护


网站公告

今日签到

点亮在社区的每一天
去签到