# Django 5.2.8 ドキュメント

# 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

制約のインデックスタイプです。受け入れられる値は `GIST` または `SPGIST` です。大文字小文字を区別しません。指定されていない場合、デフォルトのインデックスタイプは `GIST` です。

### `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` は GiST インデックスでサポートされています。PostgreSQL 14+ では、SP-GiST インデックスでも `include` がサポートされています。

### `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),
                ),
            ]