2015-01-01 110 views
13

我一直在研究Django Web應用程序的離線版本,並且經常刪除某個ModelX的模型實例。刪除所有實例後,Django模型實例主鍵不會重置爲1

我已經從管理頁面做了這個,並沒有遇到任何問題。該模型只有兩個字段:名稱和順序,與其他模型沒有其他關係。

爲新實例提供了下一個可用的pk,這是合理的,當我刪除所有實例時,添加一個新實例會得到一個pk = 1,這是我期望的。

將代碼在線移動到我的實際數據庫我注意到情況並非如此。我需要更改模型實例,所以我刪除它們,但令我驚訝的是主鍵不斷增加而不重置爲1.

使用Django API進入數據庫我已檢查並且舊實例消失,但即使添加新實例也會產生一個主鍵,該主鍵提取最後一次刪除實例的位置,而不是1.

想知道是否有人知道這裏可能存在什麼問題。

回答

14

正如其他人所說,這完全是數據庫的責任。

但您應該認識到,這是理想的行爲。一個ID唯一標識數據庫中的一個實體。因此,它應該只涉及一行。如果該行隨後被刪除,那麼沒有理由爲什麼您需要一個新行來重新使用該ID:如果您這樣做了,那麼您會在現在被刪除的實體之間創建一個混淆,該實體具有該ID,新創建一個重用它。這樣做沒有意義,你不應該這樣做。

+0

我不明白爲什麼離線版本的行爲方式與在線版本不一樣。 – pj2452

+0

使用需要在數據庫中產生某些測試數據的單元測試會是一種情況,除非您想要在每次測試中生成一個新表。 – Mehdi

+0

您是否在開發中使用與生產中相同的數據庫?特別是sqlite釋放被刪除對象的鍵以供重用(不幸的是,如果你依賴於鍵的唯一性)。 https://sqlite.org/autoinc.html – DylanYoung

3

實際上你是從數據庫中刪除它們還是使用Django刪除它們? Django的將不只是從它刪除行更改AUTO_INCREMENT爲表格,所以如果你想重置主鍵,你可能要進入你的數據庫和:

ALTER TABLE <my-table> AUTO_INCREMENT = 1; 

(這裏假設你正在使用MySQL或類似的)。

+0

謝謝。我通過Django管理頁面刪除了這些實例。這不能通過Django API完成嗎? – pj2452

+0

據我所知,並不是如此 - 但請參閱@ knbk的答案,即使用'manage.py'刪除和重新創建表。除非你真的需要主鍵來獲取特定的值,否則最好不要擔心它們不是從1開始。 – xnx

+0

如上所述,pk生成策略與Django無關,除非該DB沒有本地自動增量支持。數據庫後端將確定密鑰的回收方式。 – DylanYoung

17

我不會說這是一個問題。這是許多數據庫系統的默認行爲。基本上,表的自動增量計數器是持久的,並且刪除條目不會影響計數器。主鍵的實際價值不會影響性能或任何事情,它只具有美學價值(如果你達到20億的限制,你很可能會擔心其他問題)。

如果你真的要重置計數器,你可以刪除並重新創建表:

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

或者,如果你需要保持與其他表中的數據的應用程序,你可以手動重置計數器:

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

你在離線和在線應用程序看到不同的行爲,最可能的原因,就是自動遞增值僅存儲在內存中,而不是在磁盤上。每次重新啓動數據庫服務器時,都會重新計算爲MAX(<column>) + 1。如果該表爲空,則在重新啓動時將完全重置。對於您的離線環境而言,這可能非常常見,而對於您的在線環境則無此功能。

+0

謝謝。我只是好奇爲什麼我看到我的在線/離線版本之間的不同功能。 – pj2452

+0

@ pj2452你離線使用哪種數據庫引擎? – knbk

+0

@ pj2452 Nvm,這可能是因爲離線環境中的數據庫服務器經常重新啓動。我更新了我的答案以反映這一點。 – knbk

3

沒有問題,這就是數據庫的工作方式。 Django與生成ids沒有任何關係,它只是告訴數據庫插入一行,並從數據庫中獲取ID作爲響應。每個表的id從1開始,每次插入一行時都會增加。刪除行不會導致該標識返回。您通常不應該擔心這一點,您只需要知道每行都有唯一的ID。
您當然可以使用數據庫命令更改生成表的id的計數器,這取決於您使用的特定數據庫系統。

+0

如上所述,我知道這是默認行爲,但我不明白爲什麼離線/在線有所不同。 – pj2452

+0

您的本地數據庫將完全相同,並且不會重新分配ID。您可能已經重新創建了整個數據庫。 – nima

+0

sqlite採用現有的最高ID + 1,所以這個答案不完全正確。刪除最高ID行將導致下一個創建的行使用相同的ID。 – DylanYoung

0

我不知道這個時候加入,但下面的管理命令將所有表中刪除所有數據,如果你正在使用SQLite可以自動遞增計數器將重置爲1

./manage.py sqlflush | psql DATABASE_NAME 
+1

幾乎:它會刪除所有表中的所有數據*除了遷移表(保留原因顯而易見)(該命令專門用於保留遷移表,如果不需要保存,那麼你不需要刷新,你只需要一個dropdb + createdb,然後是'manage migrate') –

+0

好的,謝謝澄清! –

1

使用以下shell命令重置主鍵:

DELETE FROM your_table; DELETE FROM SQLite_sequence WHERE name ='your_table';