使用Python-Django将CSV文件导入到PostgreSQL数据库

7

注意: 请往下滚动至背景章节,了解有用的细节。假设此项目使用Python-Django和South,在下面的示例中。

以下CSV文件应该如何最佳导入?

"john","doe","savings","personal"
"john","doe","savings","business"
"john","doe","checking","personal"
"john","doe","checking","business"
"jemma","donut","checking","personal"

将相关表“Person”、“Account”和“AccountType”导入到PostgreSQL数据库中,并考虑以下内容:
1.管理员用户可以通过自定义UI实时更改数据库模型和CSV导入表示法 2.常规用户导入CSV文件时使用保存的CSV到数据库表/字段映射
迄今为止已经考虑了两种方法:
1. ETL-API方法:提供ETL API、电子表格、我的CSV到数据库表/字段映射以及目标数据库的连接信息。然后,API将加载电子表格并填充目标数据库表。从pygrametl的角度来看,我不认为我想要的是可能的。事实上,我不确定有任何ETL API可以做到这一点。
2.行级插入方法:解析CSV到数据库表/字段映射,解析电子表格,并按“联接顺序”生成SQL插入。
我已经实施了第二种方法,但在算法缺陷和代码复杂性方面遇到困难。是否有一个Python ETL API能够实现我想要的功能?或者有没有一种方法不涉及重新发明轮子?
背景
我工作的公司正在寻求将托管在SharePoint中的数百个项目特定设计电子表格移动到数据库中。我们即将完成一个Web应用程序,通过允许管理员为每个项目定义/建模数据库,存储其中的电子表格,并定义浏览体验来满足这一需求。在完成这个阶段转向商业工具不是一个选择。将Web应用程序视为django-admin的替代品,虽然它不是,但具有DB建模UI、CSV导入/导出功能、可定制的浏览以及模块化的代码以解决项目特定的自定义。实施的CSV导入界面很麻烦且存在错误,因此我正在尝试获取反馈并查找其他解决方法。

我认为你应该具体化问题。提取一个你正在寻找的最小示例并发布它。也就是说,编写一个CSV样本数据和规范化所需的目标模式。 - dani herrera
谢谢您的建议。希望这能得到更多关注。顺便改一下标题。 - Mario Aguilera
这个问题仍然没有意义。设计一个模式,将其放置并使用它 - 这是一个三行代码或者 psql 调用。 - Dirk Eddelbuettel
这不是一个三行代码的问题,而是一款为财富500强公司开发的企业级Web应用程序。模式是动态的,以适应业务需求,它并非一开始就是这样的,只有管理员可以通过用户界面进行更改。CSV导入解决方案很复杂,因为模式是动态的,无法避免。您提供的代码使用了静态模式,并未包含CSV导入代码。如果您对如何澄清问题有建议,我很乐意加以整合。 - Mario Aguilera
让我担心的是,到目前为止您没有任何具体/唯一的标识符。在这两个示例中,前两个字段表示同一个人、不同的人还是未知的?"john","doe","savings","personal""john","doe","savings","business" - Jonathan Vanasco
这只是一个例子,请假设唯一性。 - Mario Aguilera
4个回答

2
将问题分成两个独立的问题会怎样呢?
创建一个Person类来代表数据库中的人员。这可以使用Django的ORM,或者扩展它,或者您可以自己编写代码。
现在你有两个问题:
1.从CSV文件中创建一个Person实例。 2.将Person实例保存到数据库中。
现在,不仅是CSV到数据库的转换,而是CSV到Person和Person到数据库的转换。我认为这更加清晰易懂。当管理员更改模式时,这会影响到Person-to-Database这一侧。当管理员更改CSV格式时,他们正在更改CSV-to-Database这一侧。现在您可以单独处理每个问题。
这对您有所帮助吗?

人将是许多动态创建的对象之一,因为整个模型都是动态的;不仅仅是字段,表也是如此。由于每个对象都是一个实例,并且对象在层次上相关联,因此持久性将要求在树的每个“步骤”处进行行级插入。这绝对值得考虑,并且与行级插入方法非常相似。 - Mario Aguilera
希望我能将赏金提高到100,以提供更好的激励。 - Mario Aguilera
为什么您有管理员可以完全更改模式的要求?也许了解这一点会帮助我想到一些东西。 - Claudiu
该网络应用程序替代了一个SharePoint存储库,用于维护大量包含业务驱动项目数据的Excel电子表格。最初,该应用程序跟踪单个项目。随着时间的推移,该项目和使用的电子表格发生了变化,需要支持动态字段。随着范围扩大,包括其他项目,很明显需要正确的解决方案是具有模块化项目逻辑的模型不可知工具。简而言之,该应用程序是专有的数据库建模工具,具有导入、浏览、导出和搜索接口;以及模块化的项目特定“业务逻辑”。 - Mario Aguilera
当前的动态模型在需要它们的代码中实际上是如何使用的?它们是否运行自定义SQL查询并在管理员更改架构时更新这些查询?它们是否直接操作.csv文件,并在这些文件更改时更改其代码?它们是否有ORM,需要在模型更改时进行更新? - Claudiu
自定义模式管理UI用于通过South创建、修改和提交对已加载的模型和底层数据库的更改。这些模型是通过内省数据库动态加载的,因此数据库决定了加载的模型;Models.py不再与数据库同步,因为它始终与数据库同步,同时我可以访问ORM。 - Mario Aguilera

0
在工作中,我几乎每个月都要编写导入子系统,由于这类任务太频繁,所以我前段时间写了django-data-importer。这个导入器类似于django表单,具有读取CSV、XLS和XLSX文件的功能,可以提供字典列表。
使用data_importer阅读器,您可以将文件读取为字典列表,在其中进行迭代,并保存到数据库中。 使用导入程序,您也可以做同样的事情,但是可以验证每行字段,记录错误和操作,并在最后保存。
请看 https://github.com/chronossc/django-data-importer。我非常确定它可以解决您的问题,并帮助您从现在开始处理各种csv文件:)
为了解决您的问题,我建议使用celery任务来使用data-importer。您上传文件并通过简单的界面启动导入任务。Celery任务将文件发送到导入器,您可以验证行、保存行、记录错误。通过一些努力,您甚至可以向上载该表的用户呈现任务进度。

1
我需要解决的问题是如何智能地根据映射将整个CSV数据集提交到数据库中,映射定义了每个字段所属的表以及这些表之间的关系。您的导入工具可以为_Row级插入方法_的更清洁实现做出贡献。 - Mario Aguilera
导入器在这一点上可能没有帮助,因为它期望有一个定义范围的字段,但是data_importer.readers会有所帮助。由于它将每行作为字典返回,你可以拥有像{'fieldname': <function>, ...}这样的字典,并在循环中调用functions_dict[fieldname](fieldvalue, row)。该函数将在正确的位置保存数据,以下是一个示例:https://gist.github.com/chronossc/5208763你可以通过仅对实例进行值分配的函数来改进它,并在所有操作完成后保存实例。 - chronossc

0

我最终采取了一些措施来解决这个问题,使用可更新的SQL视图来遵循奥卡姆剃刀原则。这意味着需要做出一些牺牲:

  1. 删除:South.DB依赖的实时模式管理API、动态模型加载和动态ORM同步
  2. 手动定义models.py和一个初始的south迁移。

这样可以简单地将平面数据集(CSV/Excel)导入到规范化的数据库中:

  1. 在models.py中为每个电子表格定义未管理的模型
  2. 将这些映射到可更新的SQL视图(INSERT/UPDATE-INSTEAD SQL RULEs),这些视图遵循电子表格字段布局
  3. 通过CSV/Excel电子表格行进行迭代,并执行INSERT INTO <VIEW> (<COLUMNS>) VALUES (<CSV-ROW-FIELDS>);

0

这里有另一种方法,我在github上找到的。基本上它会检测模式并允许覆盖。它的整个目标就是生成原始的SQL语句,以便由psql和/或任何驱动程序执行。

https://github.com/nmccready/csv2psql

  % python setup.py install
  % csv2psql --schema=public --key=student_id,class_id example/enrolled.csv > enrolled.sql
  % psql -f enrolled.sql

还有许多选项可用于执行更改(从许多现有列创建主键)和合并/转储。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接