【Python・Django】中間テーブルのプライマリキーを後からID→UUIDに変更したい

【Python・Django】中間テーブルのプライマリキーを後からID→UUIDに変更したい

環境

Python:3.6
Django:2.1

やりたいこと

Djangoを使って開発を行っていましたが、最初は中間テーブルのプライマリキーをデフォルトのIDで使っていたものの、セキュリティ上の懸念に後から気がつき、変更ID→UUIDに変更したくなってしまった。

開発環境ではDB作り直せばよいのですが、せっかくなので消さずに修正を行ってみました。

※UUIDは確率論的に重複することのないランダムな値です。Webサービス等でIDをそのまま使っていた場合は、IDをベースにDBサイズやテーブル内容の推測、それに伴う攻撃が考えられるらしいです。

※今回は中間テーブルのIDのため、外部キーの被参照先となっていません。外部キーの被参照先となっている場合の検証はしていませんが、恐らくうまく動作しません

作業手順

前提と考え

以下のようにthroughを定義して中間テーブルを独自に定義しているモデルがあるとします。
(もししていなかった場合は定義する必要があります。)

以下のようにidをUUIDに書き換えるてマイグレーションを行うのですが、そのままだとユニーク制約にひっかかってエラーが出てしまいます。

Djangoのマイグレーションではカラム追加時に各行にユニークな値を入れるということが出来ません
そのため、面倒ですが以下の手順を踏む必要があります。

  1. uuid列を初期かつ編集可能としてマイグレーションを実行
  2. uuid列に本来の値を設定
  3. プライマリキーが2つ出来ないように、もともとのプライマリキーを削除
  4. uuid列をプライマリキーに設定し、編集不可とする。

こうやってデフォルトのIDをUUIDに置き換える

普通に「python manage.py makemigration」を実行する

以下のようなマイグレーションファイルが出来上がる(このままだとNG)。

まずはuuidにnullとして登録するように変更。この時点で以前のプライマリキーの削除するとuuid作成時にエラーが出るのでまだ削除はしない。

uuid列に本来の値を設定しつつ、旧プライマリキーの削除と本来の制約をかけるマイグレーションファイルを作成

空のマイグレーションファイルを作成。

「python manage.py makemigrations myapp –empty」を実行すればok。
手動でファイルを作っても問題ないですが、前のマイグレーションとの依存関係もファイル内に記載されるため、コマンドで作成するのが無難。

正しいプライマリキーの設定になるようマイグレーションファイルを設定

各レコードにユニークなuuidを設定する関数を作成してそれを呼び出す形を取ります。
当然ですが、ここの値の設定次第uuidに限らず好きな値の設定が可能です。

なお、「正しい値の設定→旧プライマリキー列削除→UUID列をプライマリキーに設定」という順番で処理を書かないとエラーで実行出来ないので要注意。

マイグレーションを実行

以上で必要なDBの操作はすべてマイグレーションファイルに記載が出来ましたので、通常通り
「python manage.py migrate」を実行すればきちんとuuidに一意な値が格納されています。

参考

https://docs.djangoproject.com/en/2.0/howto/writing-migrations/#migrations-that-add-unique-fields

http://www.denzow.me/entry/2017/12/23/150501

なかなか骨が折れますな。。きちんと設計はしようということですね…

Djangoカテゴリの最新記事