Django、Postgresql与完整性错误

3 投票
2 回答
1575 浏览
提问于 2025-04-17 06:35

我之前用的是mysql数据库,如果我想插入一条记录,可以用一个叫INSERT IGNORE的命令,这样我就可以直接把数据放进去,如果出现冲突就直接忽略掉。

现在我在做一个Django项目,使用的是postgresql数据库,并且在一个循环里进行多次保存。不过,我觉得如果出现了IntegrityError(我在代码中是忽略这个错误的),那么我可能会丢失很多我想插入的对象……我该怎么解决这个问题呢:

for thing in things:
    try:
        #potentially dangerous save..
        obj = Thing(stuff=10)
        obj.save()
    except IntegrityError:
        pass

假设在循环的第5次时出现了IntegrityError,那么哪些对象会被插入到数据库里呢?

2 个回答

1

通过不忽略错误?

你写的代码大概是这样的。

You:    Save all the things.
Django: You're about to violate data integrity in your database.
You:    I don't care.
Django: I can't simply corrupt your data. I'll just throw away 
        the things that would corrupt your data.
You:    That's what I wanted.

虽然这种做法在某些应用中可能合适,但对大多数情况来说并不合适。

你需要决定当数据不符合你的完整性约束时,应该怎么处理这些数据。同时,你还需要修复那些让不良数据进入save()方法的代码。关于这个问题,查看一下表单和字段验证的文档可能会有帮助。

8

这要看你是怎么管理你的事务的。

在Postgres数据库中,如果事务中的某个查询出错,后面的所有查询也会失败,并显示错误信息“当前事务已中止,查询在事务块结束前会被忽略”。

为了处理这个问题,你应该在异常处理块中使用transaction.savepoint_rollback。

具体可以参考Django的文档,里面有关于如何在PostgreSQL事务中处理异常的说明,链接在这里:处理PostgreSQL事务中的异常

文档中有一个示例:

a.save() # Succeeds, and never undone by savepoint rollback
try:
    sid = transaction.savepoint()
    b.save() # Could throw exception
    transaction.savepoint_commit(sid)
except IntegrityError:
    transaction.savepoint_rollback(sid)
c.save() # Succeeds, and a.save() is never undone

撰写回答