50:一意制約をつける

「本番環境で想定しないデータが入ってしまい、エラーになったようです」

このような障害報告を聞いたことがある人は、少なくないと思います。 その問題点と、解決方法を説明します。もし「まだ聞いたことがない」という方は先に勉強して、将来の問題を回避しましょう。

具体的な失敗

class Product(models.Model):
    ...


class Review(models.Model):
    product = models.ForeignKey(Product)
    user = models.ForeignKey(User)

このテーブル設計では、1つの商品に対して同じユーザーが複数のレビューを投稿できてしまいます。 1人のユーザーが評価を上げる(下げる)ために複数投稿できる問題があります。

ベストプラクティス

仕様上、想定しないデータであればできるだけ一意制約をつけておきましょう。

class Review(models.Model):
     product = models.ForeignKey(Product)
     user = models.ForeignKey(User)

     class Meta:
         constraints = [
             models.UniqueConstraint(
                 fields=["product", "user"],
                 name="unique_product_review"
             ),
         ]

一意制約 があればアプリケーション側で扱う状態を減らせます。

cover

(中略)詳細は書籍 自走プログラマー をご参照ください