尝试使用SQLAlchemy重用主键ID时出现问题

时间:2011-05-27 21:21:34

标签: python postgresql sqlalchemy

我正在尝试使用SQLAlchemy在我的一个表中重用主键,并且出现外键约束错误。

简而言之:

  • PostgreSQL 8.4
  • Python 2.7
  • SQLAlchemy 0.7

我有3个表:用户,库存和设备。库存和设备与用户具有一对一的关系。 User.id是Inventories.user_id和Devices.user_id外键。

我已经在模型中设置了用户,设备和库存/根据标准的python实践。

在交互式python中我可以发出以下命令没问题:

>>>newUser = User.create()
>>>newUser.device = User.create_device(<*args>)
>>>Session.add(newUser)
>>>Session.commit()

(在代码中自动创建库存记录)

现在,假设我想重新使用用户记录1(这是唯一允许在代码中出现安全和内部测试原因的重置方法的记录)

>>>oldUser = User.retrieve(1)
>>>Session.delete(oldUser)
>>>Session.commit()

(确认用户1不再存在)

>>>newUser = User.create()
>>>newUser.device = User.create_device(<*args>)
>>>newUser.id = 1
>>>Session.add(newUser)
>>>Session.commit()

此时我会得到一个错误,即Key(id)=(<id>)仍然从表“devices”(或“inventoryories”)引用,其中<id>是newUser。在重新分配为id 1之前的id

我已经考虑了级联,并尝试了各种选项(所有,保存更新等),但没有效果。

任何有关我出错的信息都会非常感激,

谢谢,

Krys

3 个答案:

答案 0 :(得分:0)

要解决您看到的错误,您可以在提交之前更新与该Device模型关联的所有InventoryUser模型上的外键。您必须确保您的User模型不会自动增加id(即,它不是PostgreSQL序列)。

例如,SQLAlchemy模型声明应为

class User(base):
    __tablename__ = 'user'
    id = Column('id', Integer, primary_key=True, unique=True, nullable=False)

而不是

class User(base):
    __tablename__ = 'user'
    id = Column('id', Integer, Sequence('user_id_seq'), primary_key=True)

但是,这可能不是正确的方法!在User.id上使用序列(如第二个模型声明中)更好的设计,并在用户表上添加另一个字段,指示用户是否为管理员(出于安全/测试的目的,您提到了)。这样,您就不必依赖应用程序中的幻数(例如,用户ID)来处理应用程序逻辑,尤其是安全性。

答案 1 :(得分:0)

我没有使用SQLAlchemy,所以我没有正确的答案,但我可以说你必须问自己你想要的是真的有必要吗?

由于,

  • 您可能会破坏数据完整性,这可能会导致严重的问题。
  • 您需要打破ID的自动增量结构,因此在此之前,您必须手动分配id或使用手写的预保存触发器来获取正确的ID。
  • 如果您的表格具有用户foreginkey 设置NOT null,那么您可能会遇到释放与已删除用户相关的记录的问题。如果你没有将它们归零,重用的id会产生严重的数据完整性问题(错误的依赖关系)......

首先,你必须决定它是否值得吗?

答案 2 :(得分:0)

由于这是生产中不应该出现的问题,只需使用SET CONSTRAINTS即可。您可以在FOREIGN KEY上使用INITIALLY DEFERRED,但我不建议您这样做,因为您没有处理生产中存在的循环依赖。