---
title: "PostgreSQL 固有のデータベース制約"
version: 5.0
locale: ja
source: https://docs.djangoproject.com/ja/5.0/ref/contrib/postgres/constraints/
canonical: https://djangodocs.dev/ja/5.0/ref/contrib/postgres/constraints/
---
# PostgreSQL 固有のデータベース制約

PostgreSQL は `django.contrib.postgres.constraints` モジュールから利用できる追加のデータ整合性制約をサポートしています。これらはモデル [`Meta.constraints`](/ja/5.0/ref/models/options/#django.db.models.Options.constraints) オプションで追加されます。

## `ExclusionConstraint`

#### `class ExclusionConstraint(* (Keyword-only parameters separator (PEP 3102)), name, expressions, index_type=None, condition=None, deferrable=None, include=None, violation_error_code=None, violation_error_message=None)`

データベースに排他制約を作成します。内部的には、PostgreSQLはインデックスを使用して排他制約を実装しています。デフォルトのインデックス型は [GiST](https://www.postgresql.org/docs/current/gist.html) です。インデックスを使用するには、PostgreSQLで [btree\_gist extension](https://www.postgresql.org/docs/current/btree-gist.html) を有効にする必要があります。 [`BtreeGistExtension`](/ja/5.0/ref/contrib/postgres/operations/#django.contrib.postgres.operations.BtreeGistExtension) マイグレーションオペレーションを使ってインストールできます。

既存の行と競合する新しい行を挿入しようとすると、[`IntegrityError`](/ja/5.0/ref/exceptions/#django.db.IntegrityError) が発生します。更新が既存の行と競合する場合も同様です。

排他制約は [モデル バリデーション](/ja/5.0/ref/models/instances/#validating-objects) の間にチェックされます。

### `name`

#### `ExclusionConstraint.name`

[`BaseConstraint.name`](/ja/5.0/ref/models/constraints/#django.db.models.BaseConstraint.name) を参照。

### `expressions`

#### `ExclusionConstraint.expressions`

2値タプルのイテラブル。最初の要素は式または文字列。2番目の要素は文字列で表現された SQL 演算子です。タイプミスを避けるために、演算子を文字列でマップする [`RangeOperators`](/ja/5.0/ref/contrib/postgres/fields/#django.contrib.postgres.fields.RangeOperators) を使用できます。たとえば:

```
expressions = [
    ("timespan", RangeOperators.ADJACENT_TO),
    (F("room"), RangeOperators.EQUAL),
]
```

> **演算子の制約**
>
> 排他制約には可換演算子のみ使用できます。

[`OpClass()`](/ja/5.0/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.OpClass) 式は、制約式のカスタム [operator class](https://www.postgresql.org/docs/current/indexes-opclass.html) を指定するために使用できます。たとえば:

```
expressions = [
    (OpClass("circle", name="circle_ops"), RangeOperators.OVERLAPS),
]
```

これは `circle_ops` を使用して `circle` 上に排他制約を作成します。

### `index_type`

#### `ExclusionConstraint.index_type`

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

### `condition`

#### `ExclusionConstraint.condition`

行の一部に制約をかける条件を指定する [`Q`](/ja/5.0/ref/models/querysets/#django.db.models.Q) オブジェクト。たとえば、 `condition=Q(cancelled=False)` 。

これらの条件は、 [`django.db.models.Index.condition`](/ja/5.0/ref/models/indexes/#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) 制約は、すべてのコマンドの直後に実行されます。

> **Warning**
>
> 排他制約の遅延は、パフォーマンスの悪化 [performance penalty](https://www.postgresql.org/docs/current/sql-createtable.html#id-1.9.3.85.9.4) につながるかも知れません。

### `include`

#### `ExclusionConstraint.include`

非キー列としてカバリング排他制約に含めるフィールド名のリストまたはタプル。これにより、含まれるフィールドのみを選択し ([`include`](#django.contrib.postgres.constraints.ExclusionConstraint.include))、インデックス化されたフィールドのみでフィルタリングする ([`expressions`](#django.contrib.postgres.constraints.ExclusionConstraint.expressions)) クエリにインデックスのみのスキャンを使用できます。

`include` は GiST インデックスでサポートされています。PostgreSQL 14+ では、SP-GiST インデックスでも `include` がサポートされています。

### `violation_error_code`

> **New in Django 5.0**

#### `ExclusionConstraint.violation_error_code`

[モデルのバリデーション](/ja/5.0/ref/models/instances/#validating-objects) 中に `ValidationError` が発生した場合に使用されるエラーコードです。デフォルトは `None` です。

### `violation_error_message`

[モデルのバリデーション](/ja/5.0/ref/models/instances/#validating-objects) 中に `ValidationError` が発生した場合に使用されるエラーメッセージです。デフォルトは [`BaseConstraint.violation_error_message`](/ja/5.0/ref/models/constraints/#django.db.models.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()`) を使用する式を記述し、フィールドの区切り文字を使用する必要があります。ほとんどの場合、区切り文字は `'[)'` となり、下限は包括的で上限は排他的であることを意味します。 [範囲境界](https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-INCLUSIVITY) の式マッピングを提供する  [`RangeBoundary`](/ja/5.0/ref/contrib/postgres/fields/#django.contrib.postgres.fields.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),
            ),
        ]
```
