2015-01-01 18 views
13

私はDjango Webアプリケーションのオフラインバージョンで作業しており、特定のModelXのモデルインスタンスを頻繁に削除しています。Djangoモデルインスタンスのプライマリキーは、すべてのインスタンスが削除された後に1にリセットされません。

私は管理ページからこれを行い、問題は発生していません。モデルには、名前と注文の2つのフィールドしかありません。他のモデルとの他の関係はありません。

新しいインスタンスには利用可能な次のpkが与えられます。すべてのインスタンスを削除すると、新しいインスタンスを追加すると期待されるpk = 1が得られます。

私の実際のデータベースにオンラインでコードを移動すると、私はこれが当てはまらないことに気付きました。モデルインスタンスを変更する必要がありましたが、私は驚いたことに、プライマリキーを1に戻さずにインクリメントし続けました。

Django APIを使用してデータベースにアクセスしました。新しいインスタンスを追加しても、最後に削除されたインスタンスが1の代わりに削除された主キーが生成されます。

ここで問題が何であるか知っている人がいるかどうかわかりません。

答えて

14

他の人が述べたように、これは完全にデータベースの責任です。

これはの望ましいの動作であることがわかります。 IDは、データベース内のエンティティを一意に識別します。このように、1つの行のみを参照すべきです。その行が後で削除されると、新しい行でそのIDを再利用する必要がある理由はありません。そうした場合、そのIDを使用していた現在削除されたエンティティと新たに作成したものを再利用しています。これを行うことに意味がないので、そうしたくないはずです。これを添加した場合

+0

私が理解していないのは、オフラインバージョンがオンラインバージョンと同じように動作していない理由です。 – pj2452

+0

単位テストを使用すると、すべてのテストで新しいテーブルを生成しない限り、データベースに特定のテストデータを生成する必要があります。 – Mehdi

+0

開発中に本番データベースと同じデータベースを使用していますか?特に、sqliteは、削除されたオブジェクトのキーを再利用するために解放します(残念なことに、キーの一意性に依存する場合)。 https://sqlite.org/autoinc.html – DylanYoung

3

実際にデータベースから削除したのですか、またはDjangoを使用して削除しましたか?

ALTER TABLE <my-table> AUTO_INCREMENT = 1; 

(これは、あなたが使用している前提としています。あなたはあなたの主キーをリセットしたい場合は、あなたがあなたのDBに行くとする必要がある場合がありますので、Djangoは、それから行を削除することによって、あなたのテーブルのためのAUTO_INCREMENTを変更しませんMySQLなど)。

+0

ありがとうございました。私はDjangoの管理ページからインスタンスを削除しました。 Django APIでこれを行うことはできませんか? – pj2452

+0

私が知っている限りではありませんが、 'manage.py'を使ってテーブルを削除して再作成するための@knbkの答えを見てください。プライマリキーが特定の値を取ることを本当に必要としない限り、1から始まらないことを心配しない方が良いでしょう。 – xnx

+0

上記のように、pk生成ポリシーはDjangoとほとんど関係ありません。 。データベースのバックエンドは、キーのリサイクル方法を決定します。 – 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はidを生成することと何も関係がありません。idは、データベースに行を挿入するように指示し、データベースからの応答としてidを取得します。 idはテーブルごとに1から始まり、行を挿入するたびに増加します。行を削除しても、IDは元に戻りません。あなたはそれに心配するべきではありません。知っておくべきことは、各行にユニークなIDがあることです。
データベースコマンドを使用して、テーブルのidを生成するカウンタを変更することはもちろん、使用している特定のデータベースシステムに依存します。

+0

上記のように、これはデフォルトの動作であることを理解していますが、なぜオフライン/オンラインが異なるのか分かりません。 – pj2452

+0

ローカルデータベースはまったく同じように動作し、IDの再割り当ては行われません。データベース全体を再作成した可能性があります。 – nima

+0

sqliteは既存のid + 1の中で最も高い値を取るため、この答えは完全ではありません。最高ID行を削除すると、同じIDが次に作成された行に使用されます。 – DylanYoung

0

は私はわからないんだけど、次の管理コマンドは、すべてのテーブルからすべてのデータが削除されます、あなたはあなたができるSQLiteのを使用している場合1.

./manage.py sqlflush | psql DATABASE_NAME 
+1

Almost:明示的な理由で保存されている移行テーブルを除くすべてのテーブル*からすべてのデータを削除します(このコマンドは特に移行テーブルを保持するために存在します)。あなたはフラッシュする必要はありません保存する必要があります、あなたはちょうどdropdb + createdb、 'manage migrate'の後に必要です) –

+0

良い点、明確化のおかげで! –

1

に自動インクリメントカウンタをリセットします次のシェルコマンドでプライマリキーをリセットします。

あなたのテーブルから削除します。 SQLite_sequenceから削除WHERE name = 'your_table';

関連する問題