python – 导入文件时在Django中使用事务

我正在构建一个Django应用程序,用户将导入Excel / CSV文件.每行通过如
here(底部的实施例3)所述的形式进料.

对于我的导入程序,我首先浏览整个文件,然后在表中显示任何错误.如果没有错误,我会显示将要导入的内容的摘要.用户可以确认并导入文件.问题是,行相互依赖于验证(唯一性约束等),因此我必须将每行保存到DB以使验证工作.

我已经提出了下面的方法,但我之前没有使用原子事务,我担心潜在的问题.我可以导入多达10 000行.

代码是否适合我想要达到的目标,还是有更好的方法?

def import_from_csv(filename, preview):
    sid = transaction.savepoint()
    result = import_data(filename)
    if result.has_error or preview:
        transaction.savepoint_rollback(sid)
    else:
        transaction.savepoint_commit(sid)
    return result

附加信息:

在我的应用程序中有两个不同意见.第一个视图是预览视图.在这种情况下,我将预览设置为True调用import_from_csv.这样插入件将始终回滚.它返回已导入的结果.如果没有错误,我将文件的位置保存在会话变量中.如果用户单击确认,我再次调用import_from_csv,但这次预览为False.由于我已经在预览步骤中检查了文件,因此不应该有任何错误,并且将提交结果.我知道这可以优化,因为我正在处理文件两次.

我正在使用Django 1.9和Postgres(在Heroku上)

最佳答案 得到1

无论数据库是什么,插入10,000行都不会非常快.你可能只能在超时之前把它挤进来,但是你有机会.

陷阱2

在事务中,一旦发生错误,该事务不能用于进一步插入,直到您回滚.如果CSV中的第二行导致错误,您会发现实际上没有插入任何内容.

根据您的最新信息:

您仍然很难确定哪些记录可以插入,哪些记录不可以.您可能需要在import_data中进行自动提交,这会进一步降低速度.

得到3

该方法实际上没有为用户提供确认或拒绝插入的机会.用户操作将由单独的HTTP请求处理.它与发送CSV数据的不同.结果,在此时间内收到用户操作,此事务已完成并且已粉碎并且无法回滚.

得4

如果前面的行依赖于后面的行(你说行之间可能存在关系),那么插入将失败.

使用数据库批量加载来填充临时表,除了约束之外,该表与真实表相同.您尚未指定数据库是什么.例如,在postgresql中批量加载的方法是COPY FROM,在mysql中是LOAD DATA.

加载数据后,将约束添加到临时表.与原始表进行连接以确定哪些行是重复的.询问用户是否忽略或更新重复项.然后执行INSERT SELECT

对提供的其他信息的回应:

如果您正在使用芹菜任务,则可能不依赖于COPY,但最初导入临时表仍然会更好.这样就可以避免两次处理数据的需要.并且很容易弄清楚CSV文件中的哪些行会导致重复.

点赞