初心者のためのDjango入門
■第9話:Modelにおける制約の作成
(最終更新日:2023.07.30)
(絵が小さい場合はスマホを横に)
「重複を防ぎたい!」
データベースを扱う際、同一フィールド内で重複(同じ値の登録)を防ぐにはユニークキーを設定する。
ただし、「苗字と名前の両方が一致した場合の重複を阻止する」「部屋の番号と予約時間の両方が一致した場合の重複を阻止する」といった、
複数フィールドにまたがる重複の制御は対応できない。
そんなときに役立つ機能がDjangoのConstraint(制約)である。
今回はそれを可能にする、DjangoのConstraint機能について紹介していこう。
1.CheckConstraint
CheckConstraintはDjangoのQオブジェクトを使用して、特定の条件を満たしているかをチェックする機能である。
以下の例では、6歳と7歳のみ登録が可能となっており、5歳を入力するとエラーが発生する。条件を変更することで、
18歳以上のみ登録可能にしたり、12歳以下の登録を禁止することもできる。
Djangoには、MinValueValidatorやMaxValueValidatorといった最大値・最小値を設定する制約機能も存在するが、
記述が長くなり見づらくなる上、制約できる内容が限定される。
しかし、CheckConstraintとQオブジェクトを組み合わせることで、簡潔にかつ高い自由度で条件を設定できる。
見た目と機能の両面から、こちらの方法を利用することが推奨される。
CheckConstraintによる年齢のチェック
5歳は失敗(右上)、6歳で入力した際は成功(右下)
2.UniqueConstraint
今回の主題であるUniqueConstraintは、複数の項目における重複を防ぐ制約機能である。
以下の例では、姓と名の重複を防止している。
コードの記述方法としては、fieldsに重複を避けたい項目を複数指定するだけで実現できる。
姓と名の重複を防ぐ例は実際にはあまり現実的ではないが、
例えばホテルの部屋予約システムで日程と部屋を組み合わせて重複をチェックするケースなどでは、
この機能が非常に役立つだろう。複数条件における入力の重複を防止する機能として、UniqueConstraintは非常に便利である。
UniqueConstraintによる複数入力の重複チェック
3.ExclusionConstraint(PostgreSQLのみ)
最後に、ExclusionConstraintについて説明する。
この機能は、データベースにPostgreSQLを使用している場合のみ有効だ。
PostgreSQL限定の機能である、本機能のコードを示す。以下は、Django公式ドキュメントで紹介されているコードだ。
ExclusionConstraintでは、expressions部分に記述することで重複を防ぐ条件を指定できる。
UniqueConstraintとの違いは、timespanの部分で時間帯のオーバーラップを防ぐことができる点だ。
この機能により、時間範囲内での重複がある場合にエラーを発生させることができる。
また、conditionの部分はUniqueConstraintでも使用可能だが、
ExclusionConstraintの例では、キャンセルされたものを除いて重複を防ぐ制約を設定している。
普段からPostgreSQLを使用している方にとっては、便利な機能だから、ぜひ活用してみよう。
ExclusionConstraintの使用例
4.まとめ
今回は、Djangoの制約機能(Constraint)を紹介した。データベースの入力制約はとても便利だ。
DjangoのConstraintを使うことで、
「複数条件によるチェックを行う」「2つの入力情報が一致した時のみエラーを出す」「ある時間範囲の重複を除く」などの制約を簡単に設定できる。
ただ、実際のサイトでは、ホテルや美容院の予約画面で埋まっている時間には×ボタンが表示されるため、
重複した時間に予約することはない。しかし、2人がほぼ同時刻にアクセスした場合、どちらのユーザーにも〇ボタンが表示されることがある。
そんな時の重複予約を防ぐことができる。
例えば、HotpepperBeautyで予約しようとして送信ボタンを押したものの、「既に埋まってしまいました」というメッセージが出るような状況だ。
この制約機能を使うことで、間違いを防ぐ安心設計を実現できる。ぜひ実際のモデルでも活用してみよう。
▼参考図書、サイト
Constraints reference django公式ドキュメント
【Django】複数フィールドにユニーク制約(複合ユニーク)をつける方法 DjangoBrothers BLOG
PostgreSQL固有のデータベースの制約 Djangoのドキュメント