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 擴充功能。您可以使用
BtreeGistExtension
遷移操作來安裝它。如果您嘗試插入與現有列衝突的新列,則會引發
IntegrityError
。同樣地,當更新與現有列衝突時也會如此。排除約束會在模型驗證期間進行檢查。
name
¶
- ExclusionConstraint.name¶
請參閱 BaseConstraint.name
。
expressions
¶
- ExclusionConstraint.expressions¶
一個包含 2 個元素的元組的可迭代物件。第一個元素是一個表達式或字串。第二個元素是一個以字串表示的 SQL 運算子。為避免輸入錯誤,您可以使用 RangeOperators
,它將運算子與字串對應。例如
expressions = [
("timespan", RangeOperators.ADJACENT_TO),
(F("room"), RangeOperators.EQUAL),
]
運算子的限制。
只有可交換的運算子才能在排除約束中使用。
OpClass()
表達式可用於為約束表達式指定自訂的 運算子類別。例如
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,
)
預設情況下,約束不會延遲。延遲的約束在交易結束之前不會強制執行。立即的約束將在每個命令之後立即強制執行。
警告
延遲的排除約束可能會導致 效能損失。
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),
),
]
如果您的模型使用兩個欄位而不是原生 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),
),
]