本教程旨在解决使用Peewee在PostgreSQL中进行数据摄取时,父表(如`Devices`)在处理一对多关系时意外创建重复记录的问题。文章将深入分析导致重复的关键代码段,并提供一系列实用的解决方案,包括强制唯一性约束、优化“获取或创建”逻辑、利用Peewee查询日志进行调试,以及使用数据库事务来确保数据完整性。
在构建数据库后端时,常见模式是建立父子表之间的一对多关系。例如
,一个Device(设备)可以有多个Message(消息)、File(文件)或UserAccount(用户账户)记录。我们的目标是为每个唯一的物理或逻辑设备在Devices表中只保留一条记录,而其他相关信息则通过外键链接到对应的Device记录。
然而,在从外部源(如Excel电子表格)摄取数据时,如果处理不当,可能会在父表中意外创建重复的记录。本场景中,问题表现为:当从一个包含多个工作表(对应Messages、Files、UserAccounts等子表)的Excel文件摄取数据时,Devices表会为同一个逻辑设备创建多条重复记录。例如,如果一个Excel文件包含设备1的消息、文件和用户账户信息,最终Devices表中会存在3条“设备1”的记录。
为了诊断问题,我们首先审视Peewee模型定义和数据摄取的核心逻辑。
以下是Device和Message模型的简化定义,其他子表(File、UserAccount)结构类似:
import peewee
# 假设 BaseModel 包含了数据库连接配置
class BaseModel(peewee.Model):
class Meta:
database = peewee.PostgresDatabase('your_db', user='your_user', password='your_password', host='localhost', port=5432)
class Device(BaseModel):
id = peewee.AutoField()
md5 = peewee.FixedCharField(32) # 文件哈希,用于标识设备
# ... 其他设备属性
class Message(BaseModel):
id = peewee.AutoField()
dev_ref = peewee.ForeignKeyField(Device, backref="messages") # 外键关联Device
# ... 其他消息属性
# 连接数据库
BaseModel._meta.database.connect()这里,Device.md5字段被设计为源文件的哈希值,意图作为设备的唯一标识。Message.dev_ref则通过外键关联到Device表。
数据摄取通过sheet_to_model函数实现,它负责读取Excel工作表数据并将其转换为数据库记录:
import pandas as pd
import hashlib
def calculate_file_hash(file_path: str) -> str:
"""计算文件的MD5哈希值"""
with open(file_path, 'rb') as f:
return hashlib.md5(f.read()).hexdigest()
def sheet_to_model(
source_file_path: str,
sheet_name: str,
model: peewee.Model):
df = pd.read_excel(source_file_path, sheet_name=sheet_name)
file_hash = calculate_file_hash(source_file_path)
# 潜在问题区域:Device 记录的“获取或创建”逻辑
try:
device = Device.select().where(Device.md5 == file_hash).get()
except peewee.DoesNotExist: # 明确捕获 Peewee 的 DoesNotExist 异常
device = Device(md5=file_hash)
device.save()
except Exception as e:
# 记录其他潜在错误,并重新抛出或适当处理
print(f"Error getting/creating device for hash {file_hash}: {e}")
raise
# 遍历数据框行,创建子表记录
for index, row in df.iterrows():
attrs = { 'column_name' : row['excel_column_name'] } # 示例:从Excel行映射属性
# 创建子表记录,并关联到获取到的设备ID
model.create(dev_ref=device.id, **attrs)
主摄取循环遍历文件和工作表:
import glob
import openpyxl
# 示例:工作表名称到 Peewee 模型的映射
sheet_model_map = {
"Messages" : Message,
"Files" : File,
"User Accounts": UserAccounts
}
# 遍历指定目录下的所有Excel文件
for file_path in glob.glob("file/location/whatever/*.xlsx"):
# 考虑在此处使用数据库事务,以确保文件级别的数据一致性
# with BaseModel._meta.database.atomic():
xl_file = openpyxl.load_workbook(file_path, read_only=True)
for sheet_name in filter(lambda k: k in sheet_model_map, xl_file.sheetnames):
sheet_to_model(file_path, sheet_name, sheet_model_map[sheet_name])
# 关闭数据库连接
BaseModel._meta.database.close()根据问题描述,“对于从电子表格中摄取的每个新工作表,它都会在Devices表中创建重复行。”这表明,即使file_hash对于同一个源文件是相同的,Device的“获取或创建”逻辑也未能正确识别已存在的设备。
根本原因通常在于:
为了解决记录重复问题并提升数据摄取过程的健壮性,我们推荐以下解决方案和最佳实践:
防止重复的最有效方法是在数据库层面强制执行唯一性。对于Device模型的md5字段,如果它旨在作为设备的唯一标识符,那么应该为其添加unique=True约束。
class Device(BaseModel):
id = peewee.AutoField()
md5 = peewee.FixedCharField(32, unique=True) # 强制 md5 字段唯一
# ... 其他设备属性注意事项:
Peewee提供了更简洁、更安全的get_or_create()方法,专门用于处理这种“如果存在则获取,否则创建”的模式。
# 在 sheet_to_model 函数中替换现有的 try-except 块
def sheet_to_model(
source_file_path: str,
sheet_name: str,
model: peewee.Model):
df = pd.read_excel(source_file_path, sheet_name=sheet_name)
file_hash = calculate_file_hash(source_file_path)
# 使用 Peewee 的 get_or_create 方法
# 如果 md5 存在,则返回现有 device 对象;否则创建新 device
device, created = Device.get_or_create(md5=file_hash)
if created:
print(f"Created new device with md5: {file_hash}")
else:
print(f"Found existing device with md5:
# word
# excel
# 后端
# ai
# select
# try
# 标识符
# 循环
# 并发
# table
# postgresql
# 数据库
# 遍历
# 抛出
# 多个
# 会在
# 根本原因
# 的是
# 电子表格
# 是在
# 是因为
# 如果没有
相关文章:
php8.4新语法match怎么用_php8.4match表达式替代switch【方法】
深圳网站制作的公司有哪些,dido官方网站?
郑州企业网站制作公司,郑州招聘网站有哪些?
网站制作的软件有哪些,制作微信公众号除了秀米还有哪些比较好用的平台?
如何通过免费商城建站系统源码自定义网站主题与功能?
微信小程序 input输入框控件详解及实例(多种示例)
高防服务器租用首荐平台,企业级优惠套餐快速部署
制作公司内部网站有哪些,内网如何建网站?
如何零基础开发自助建站系统?完整教程解析
北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?
网站设计制作公司地址,网站建设比较好的公司都有哪些?
高配服务器限时抢购:企业级配置与回收服务一站式优惠方案
Android自定义控件实现温度旋转按钮效果
高端智能建站公司优选:品牌定制与SEO优化一站式服务
已有域名能否直接搭建网站?
Python文件管理规范_工程实践说明【指导】
韩国服务器如何优化跨境访问实现高效连接?
内部网站制作流程,如何建立公司内部网站?
Swift中swift中的switch 语句
如何使用Golang table-driven基准测试_多组数据测量函数效率
常州自助建站:操作简便模板丰富,企业个人快速搭建网站
学校免费自助建站系统:智能生成+拖拽设计+多端适配
开封网站制作公司,网络用语开封是什么意思?
建站之星五站合一营销型网站搭建攻略,流量入口全覆盖优化指南
杭州银行网站设计制作流程,杭州银行怎么开通认证方式?
建站之星价格显示格式升级,你的预算足够吗?
专业网站设计制作公司,如何制作一个企业网站,建设网站的基本步骤有哪些?
建站之星如何优化SEO以实现高效排名?
如何通过虚拟主机空间快速建站?
如何有效防御Web建站篡改攻击?
如何通过云梦建站系统实现SEO快速优化?
SAX解析器是什么,它与DOM在处理大型XML文件时有何不同?
如何快速搭建高效WAP手机网站吸引移动用户?
高防服务器租用如何选择配置与防御等级?
Python多线程使用规范_线程安全解析【教程】
视频网站制作教程,怎么样制作优酷网的小视频?
广东专业制作网站有哪些,广东省能源集团有限公司官网?
如何快速配置高效服务器建站软件?
小说建站VPS选用指南:性能对比、配置优化与建站方案解析
制作表格网站有哪些,线上表格怎么弄?
如何配置IIS站点权限与局域网访问?
金*站制作公司有哪些,金华教育集团官网?
建站VPS能否同时实现高效与安全翻墙?
如何用y主机助手快速搭建网站?
美食网站链接制作教程视频,哪个教做美食的网站比较专业点?
建站10G流量真的够用吗?如何应对访问高峰?
宝华建站服务条款解析:五站合一功能与SEO优化设置指南
较简单的网站制作软件有哪些,手机版网页制作用什么软件?
宝塔面板创建网站无法访问?如何快速排查修复?
香港服务器租用每月最低只需15元?
*请认真填写需求信息,我们会在24小时内与您取得联系。