PostgreSQL固有のデータベースの制約—Djangoのドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/ref/contrib/postgres/constraints
移動先:案内検索

PostgreSQL固有のデータベースの制約

PostgreSQLは、django.contrib.postgres.constraintsモジュールから利用できる追加のデータ整合性制約をサポートします。 これらは、モデル Meta.constraints オプションに追加されます。

ExclusionConstraint

class ExclusionConstraint(*, name, expressions, index_type=None, condition=None, deferrable=None, include=None, opclasses=())

データベースに除外制約を作成します。 内部的には、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 と同じデータベース制限があります。


deferrable

ExclusionConstraint.deferrable

バージョン3.1の新機能。


このパラメーターを設定して、延期可能な除外制約を作成します。 許容値は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,
)

デフォルトでは、制約は延期されません。 遅延制約は、トランザクションが終了するまで適用されません。 すべてのコマンドの直後に、即時制約が適用されます。

警告

除外制約を延期すると、パフォーマンスペナルティが発生する可能性があります。


include

ExclusionConstraint.include

バージョン3.2の新機能。


非キー列としてカバー除外制約に含まれるフィールドの名前のリストまたはタプル。 これにより、含まれるフィールドのみを選択し( include )、インデックス付きフィールドのみでフィルタリングする()クエリにインデックスのみのスキャンを使用できます。

includeは、PostgreSQL12以降のGiSTインデックスでのみサポートされます。


opclasses

ExclusionConstraint.opclasses

バージョン3.2の新機能。


この制約に使用する PostgreSQLオペレータークラスの名前。 カスタム演算子クラスが必要な場合は、制約内の式ごとに1つ指定する必要があります。

例えば:

ExclusionConstraint(
    name='exclude_overlapping_opclasses',
    expressions=[('circle', RangeOperators.OVERLAPS)],
    opclasses=['circle_ops'],
)

circle_opsを使用して、circleに除外制約を作成します。


次の例では、キャンセルされた予約を考慮せずに、同じ部屋での重複する予約を制限しています。

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