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)[source]¶
在数据库中创建排他约束。在内部,PostgreSQL 使用索引实现排他约束。默认索引类型为 GiST。要使用它们,您需要在 PostgreSQL 上激活 btree_gist 扩展。您可以使用
BtreeGistExtension
迁移操作安装它。如果您尝试插入与现有行冲突的新行,则会引发
IntegrityError
。类似地,当更新与现有行冲突时。在 模型验证 期间检查排他约束。
name
¶
- ExclusionConstraint.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
上使用 circle_ops
创建排他约束。
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
) 进行过滤的查询使用仅索引扫描。
GiST 索引支持 include
。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),
),
]