【问题标题】:Django model instances primary keys do not reset to 1 after all instances are deleted删除所有实例后,Django 模型实例主键不会重置为 1
【发布时间】:2015-02-28 09:13:40
【问题描述】:

我一直在开发我的 Django Web 应用程序的离线版本,并且经常删除某个 ModelX 的模型实例。

我已从管理页面完成此操作,并且没有遇到任何问题。该模型只有两个字段:名称和顺序,与其他模型没有其他关系。

新实例被赋予下一个可用的 pk,这是有意义的,当我删除所有实例后,添加新实例会产生 pk=1,这是我所期望的。

将代码在线移动到我的实际数据库中,我注意到情况并非如此。我需要更改模型实例,所以我将它们全部删除,但令我惊讶的是,主键一直在递增,而没有重置回 1。

使用我检查过的 Django API 进入数据库并且旧实例已经消失,但即使添加新实例也会产生一个主键,该主键会从上次删除的实例停止的地方开始,而不是 1。

想知道是否有人知道这里可能是什么问题。

【问题讨论】:

    标签: django primary-key models instances


    【解决方案1】:

    “POSTGRES”数据库的另一个解决方案来自 UI。 选择您的表格并查找“序列”下拉菜单,然后选择设置并以这种方式调整序列。

    示例:

    【讨论】:

      【解决方案2】:

      如果您使用 SQLite,您可以使用以下 shell 命令重置主键:

      从你的表中删除; DELETE FROM SQLite_sequence WHERE name='your_table';

      【讨论】:

        【解决方案3】:

        我不确定这是何时添加的,但以下管理命令将删除所有表中的所有数据并将自动递增计数器重置为 1。

        ./manage.py sqlflush | psql DATABASE_NAME
        

        【讨论】:

        • 几乎:删除所有表中的所有数据t需要保留然后你不需要刷新,你只需要一个dropdb + createdb,然后是manage migrate
        【解决方案4】:

        我不会称之为问题。这是许多数据库系统的默认行为。基本上,表的自增计数器是持久的,删除条目不会影响计数器。主键的实际值不会影响性能或任何东西,它只具有美学价值(如果你达到 20 亿的限制,你很可能会担心其他问题)。

        如果你真的想重置计数器,你可以删除并重新创建表:

        python manage.py sqlclear <app_name> > python manage.py dbshell
        

        或者,如果您需要保留应用中其他表中的数据,您可以手动重置计数器:

        python manage.py dbshell
        mysql> ALTER TABLE <table_name> AUTO_INCREMENT = 1;
        

        您在离线和在线应用程序中看到不同行为的最可能原因是自动增量值仅存储在内存中,而不是存储在磁盘中。每次重新启动数据库服务器时,它都会重新计算为MAX(&lt;column&gt;) + 1。如果表是空的,它将在重新启动时完全重置。这对于您的离线环境可能很常见,而对于您的在线环境几乎没有。

        【讨论】:

        • 谢谢。我只是好奇为什么我看到在线/离线版本之间的功能不同。
        • @pj2452 你在离线使用什么数据库引擎?
        • @pj2452 Nvm 那,可能是因为你的离线环境中的数据库服务器经常重启。我更新了我的答案以反映这一点。
        • 谢谢。现在我想起来这更有意义。
        【解决方案5】:

        正如其他人所说,这完全是数据库的责任。

        但你应该意识到这是理想的行为。 ID 唯一标识数据库中的实体。因此,它应该只引用一行。如果该行随后被删除,则没有理由让新行重新使用该 ID:如果这样做,您会在曾经拥有该 ID 的现已删除的实体和新创建的重复使用它。这样做没有意义,你不应该这样做。

        【讨论】:

        • 我不明白为什么离线版本的行为方式与在线版本不同。
        • 使用需要在数据库中生成某些测试数据的单元测试是一种情况,除非您想为每个测试生成一个新表。
        • 您在开发中使用与生产中相同的数据库吗?特别是 sqlite 释放已删除对象的键以供重用(不幸的是,如果您依赖于键的唯一性)。 sqlite.org/autoinc.html
        【解决方案6】:

        没有问题,这就是数据库的工作方式。 Django 与生成 id 没有任何关系,它只是告诉数据库插入一行并从数据库中获取 id 作为响应。每个表的 id 从 1 开始,每次插入一行时递增。删除行不会导致 id 返回。您通常不必担心这一点,您只需要知道每一行都有一个唯一的 ID。
        您当然可以使用数据库命令更改为您的表生成 id 的计数器,这取决于您使用的特定数据库系统。

        【讨论】:

        • 如上所述,我理解这是默认行为,但我不明白为什么离线/在线不同。
        • 您的本地数据库将完全一样,并且不会重新分配 ID。您可能已经重新创建了整个数据库。
        • sqlite 采用现有的最高 id + 1 所以这个答案并不完全正确。删除最高 id 行将导致同一 id 用于下一个创建的行。
        【解决方案7】:

        您实际上是从数据库中删除了它们还是使用 Django 删除了它们? Django 不会仅仅通过删除表中的行来更改表的AUTO_INCREMENT,因此如果你想重置主键,你可能必须进入你的数据库:

        ALTER TABLE <my-table> AUTO_INCREMENT = 1;
        

        (假设您使用的是 MySQL 或类似软件)。

        【讨论】:

        • 谢谢。我通过 Django 管理页面删除了这些实例。这不能通过 Django API 完成吗?
        • 据我所知 - 但请参阅@knbk 使用manage.py 删除和重新创建表的答案。除非您确实需要主键来获取特定值,否则最好不要担心它们不是从 1 开始。
        • 如上所述,pk 生成策略与 Django 关系不大,除非该 DB 没有原生的自动增量支持。数据库后端将确定如何回收密钥。
        猜你喜欢
        • 2013-01-07
        • 2016-12-13
        • 2011-10-21
        • 2019-02-25
        • 1970-01-01
        • 2015-11-12
        • 2012-07-26
        • 2015-11-20
        • 1970-01-01
        相关资源
        最近更新 更多