Django-モデルのプライマリキーをUUIDにする

Djangoでは、モデルのプライマリーキーがシーケンスによって決まります。

つまり下記のように、データベースに挿入されたレコードのidが連番になります。

id: 1 field: hogehgoe

id: 2 field: mogumogu …

このidをUUIDに変更します。

UUIDは次のような利点があります。

  1. 衝突の回避-UUIDの一意性はグローバルなので、異なるモデルが同じidを持つ可能性が発生しない
  2. データベーステーブルのサイズの予測を回避
  3. idの推測を回避

2について。単純に整数がインクリメントされる方式だと、データのサイズを外部から容易に推測できてしまいます。例えばidが3なら3番目のレコード、という具合にです。UUIDにすればデータベースのサイズを予測できなくなります。

3について。例えばhttps://hogehoge.com/user/profile/1という感じで、idを用いてURLを生成することがあります。このように整数だと予測が簡単なので、攻撃を受けやすくなります。しかしUUIDは予測困難なので、不正にデータへアクセスしようとする自体を防ぐことができます。

そのため、特に理由がない場合はUUIDを使うほうが良く、HerokuのPostgreSQL担当者もUUIDの使用を推奨しています。

*参考 http://postgres-bits.herokuapp.com/#58

idをuuidに変更する方法

models.pyで定義したモデルクラスで、UUIDFiledを使ってidの型を指定します。

import uuid
from django.db import models

class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # other fields

例えばAbstractBaseUserからUserモデルを拡張したケースだと、次のようになります。

import uuid
.....
class User(AbstractBaseUser, PermissionsMixin):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    .....

まとめ

とても簡単に実装できましたが、すでに稼働中のプロジェクトでUUIDに切り替えるのは難しいので、よほどの理由がない限りは避けたほうが良さそうです。開発段階や新規のプロジェクトで使っていこうと思います。