PostgreSQL固有のデータベースの制約—Djangoのドキュメント
PostgreSQL固有のデータベースの制約
PostgreSQLは、django.contrib.postgres.constraints
モジュールから利用できる追加のデータ整合性制約をサポートします。 これらは、モデル Meta.constraints オプションに追加されます。
ExclusionConstraint
バージョン3.0の新機能。
- class ExclusionConstraint(*, name, expressions, index_type=None, condition=None)
データベースに除外制約を作成します。 内部的には、PostgreSQLはインデックスを使用して除外制約を実装します。 デフォルトのインデックスタイプは GiST です。 それらを使用するには、PostgreSQLで btree_gist拡張機能をアクティブ化する必要があります。 BtreeGistExtension 移行操作を使用してインストールできます。
既存の行と競合する新しい行を挿入しようとすると、 IntegrityError が発生します。 同様に、更新が既存の行と競合する場合。
name
- ExclusionConstraint.name
制約の名前。
expressions
- ExclusionConstraint.expressions
2タプルの反復可能。 最初の要素は式または文字列です。 2番目の要素は、文字列として表されるSQL演算子です。 タイプミスを避けるために、 RangeOperators を使用して演算子を文字列にマップすることができます。 例えば:
expressions=[
('timespan', RangeOperators.ADJACENT_TO),
(F('room'), RangeOperators.EQUAL),
]
演算子の制限。
除外制約で使用できるのは可換演算子のみです。
index_type
- ExclusionConstraint.index_type
制約のインデックスタイプ。 許容値はGIST
またはSPGIST
です。 マッチングでは大文字と小文字は区別されません。 指定しない場合、デフォルトのインデックスタイプはGIST
です。
condition
- ExclusionConstraint.condition
制約を行のサブセットに制限する条件を指定する Q オブジェクト。 たとえば、condition=Q(cancelled=False)
です。
これらの条件には、 django.db.models.Index.condition と同じデータベース制限があります。
例
次の例では、キャンセルされた予約を考慮せずに、同じ部屋での重複する予約を制限しています。
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import DateTimeRangeField, RangeOperators
from django.db import models
from django.db.models import Q
class Room(models.Model):
number = models.IntegerField()
class Reservation(models.Model):
room = models.ForeignKey('Room', on_delete=models.CASCADE)
timespan = DateTimeRangeField()
cancelled = models.BooleanField(default=False)
class Meta:
constraints = [
ExclusionConstraint(
name='exclude_overlapping_reservations',
expressions=[
('timespan', RangeOperators.OVERLAPS),
('room', RangeOperators.EQUAL),
],
condition=Q(cancelled=False),
),
]
モデルがネイティブのPostgreSQL範囲タイプではなく、2つのフィールドを使用して範囲を定義する場合は、同等の関数を使用する式を作成する必要があります(例: TsTzRange()
)、フィールドの区切り文字を使用します。 ほとんどの場合、区切り文字は'[)'
になります。これは、下限が包括的で上限が排他的であることを意味します。 範囲境界の式マッピングを提供する RangeBoundary を使用できます。 例えば:
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import (
DateTimeRangeField,
RangeBoundary,
RangeOperators,
)
from django.db import models
from django.db.models import Func, Q
class TsTzRange(Func):
function = 'TSTZRANGE'
output_field = DateTimeRangeField()
class Reservation(models.Model):
room = models.ForeignKey('Room', on_delete=models.CASCADE)
start = models.DateTimeField()
end = models.DateTimeField()
cancelled = models.BooleanField(default=False)
class Meta:
constraints = [
ExclusionConstraint(
name='exclude_overlapping_reservations',
expressions=(
(TsTzRange('start', 'end', RangeBoundary()), RangeOperators.OVERLAPS),
('room', RangeOperators.EQUAL),
),
condition=Q(cancelled=False),
),
]