PostgreSQL 固有のデータベース制約¶
PostgreSQL は django.contrib.postgres.constraints モジュールから利用できる追加のデータ整合性制約をサポートしています。これらはモデル Meta.constraints オプションで追加されます。
ExclusionConstraint¶
- class ExclusionConstraint(*, name, expressions, index_type=None, condition=None, deferrable=None, include=None, violation_error_code=None, violation_error_message=None)[ソース]¶
データベースに排他制約を作成します。内部的には、PostgreSQLはインデックスを使用して排他制約を実装しています。デフォルトのインデックス型は GiST です。インデックスを使用するには、PostgreSQLで btree_gist extension を有効にする必要があります。
BtreeGistExtensionマイグレーションオペレーションを使ってインストールできます。既存の行と競合する新しい行を挿入しようとすると、
IntegrityErrorが発生します。更新が既存の行と競合する場合も同様です。排他制約は モデル バリデーション の間にチェックされます。
name¶
- ExclusionConstraint.name¶
BaseConstraint.name を参照。
expressions¶
- ExclusionConstraint.expressions¶
2値タプルのイテラブル。最初の要素は式または文字列。2番目の要素は文字列で表現された SQL 演算子です。タイプミスを避けるために、演算子を文字列でマップする RangeOperators を使用できます。たとえば:
expressions = [
("timespan", RangeOperators.ADJACENT_TO),
(F("room"), RangeOperators.EQUAL),
]
演算子の制約
排他制約には可換演算子のみ使用できます。
OpClass() 式は、制約式のカスタム operator class を指定するために使用できます。たとえば:
expressions = [
(OpClass("circle", name="circle_ops"), RangeOperators.OVERLAPS),
]
これは circle_ops を使用して circle 上に排他制約を作成します。
index_type¶
- ExclusionConstraint.index_type¶
The index type of the constraint. Accepted values are GiST, Hash, or
SPGiST. Matching is case insensitive. If not provided, the default index
type is GIST.
Support for exclusion constraints using Hash indexes was added.
condition¶
- ExclusionConstraint.condition¶
行の一部に制約をかける条件を指定する Q オブジェクト。たとえば、 condition=Q(cancelled=False) 。
これらの条件は、 django.db.models.Index.condition と同じデータベースの制約事項を持ちます。
deferrable¶
- ExclusionConstraint.deferrable¶
遅延可能な排他制約を作成するには、このパラメータを設定します。使用可能な値は Deferrable.DEFERRED または Deferrable.IMMEDIATE です。例:
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import RangeOperators
from django.db.models import Deferrable
ExclusionConstraint(
name="exclude_overlapping_deferred",
expressions=[
("timespan", RangeOperators.OVERLAPS),
],
deferrable=Deferrable.DEFERRED,
)
デフォルトでは、制約は遅延 (DEFERRED) されません。遅延された制約は、トランザクションが終了するまで実行されません。即時 (IMMEDIATE) 制約は、すべてのコマンドの直後に実行されます。
警告
排他制約の遅延は、パフォーマンスの悪化 performance penalty につながるかも知れません。
include¶
- ExclusionConstraint.include¶
非キー列としてカバリング排他制約に含めるフィールド名のリストまたはタプル。これにより、含まれるフィールドのみを選択し (include)、インデックス化されたフィールドのみでフィルタリングする (expressions) クエリにインデックスのみのスキャンを使用できます。
include is supported for GiST and SP-GiST indexes.
violation_error_code¶
- ExclusionConstraint.violation_error_code¶
モデルのバリデーション 中に ValidationError が発生した場合に使用されるエラーコードです。デフォルトは None です。
violation_error_message¶
モデルのバリデーション 中に ValidationError が発生した場合に使用されるエラーメッセージです。デフォルトは BaseConstraint.violation_error_message です。
例¶
次の例では、キャンセルされた予約を考慮せずに、同じ部屋での重複する予約を制限しています。
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),
),
]
モデルが2つのフィールドを使用して範囲を定義する場合、PostgreSQLのネイティブな範囲型ではなく、同等の関数 (例えば 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),
),
]