PostgreSQL 支持额外的数据完整性约束,可从 django.contrib.postgres.cracks 模块中获得。它们被添加到模型 Meta.constraints 选项中。
ExclusionConstraint¶在数据库中创建一个排除约束。在内部,PostgreSQL 使用索引来实现排除约束的功能。默认的索引类型是 GiST 。要使用它们,你需要激活 PostgreSQL 上的 btree_gist 扩展 。你可以使用 BtreeGistExtension 迁移操作来安装它。
如果你试图插入一条新的记录,而这条记录与现有的记录发生冲突,就会引发一个 IntegrityError。同样,当更新与现有的记录冲突时,也会发出。
排除约束在 模型验证 期间进行检查。
name¶请参阅 BaseConstraint.name。
expressions¶一个二元元组的迭代。第一个元素是一个表达式或字符串。第二个元素是一个用字符串表示的 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¶The index type of the constraint. Accepted values are GiST, Hash, or
SPGiST. Matching is case insensitive. If not provided, the default index
type is GIST.
Support for exclusion constraints using Hash indexes was added.
condition¶一个 Q 对象,用于指定将约束条件限制在行的子集上。例如,condition=Q(cancelled=False)。
这些条件与 django.db.models.Index.condition 具有相同的数据库限制。
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,
)
默认情况下,约束条件是不推迟的。推迟的约束条件在事务结束前不会被强制执行。即时约束将在每条命令后立即执行。
Warning
延迟排除约束可能导致 性能惩罚 。
include¶一个包含在覆盖排除约束中作为非键列的字段名称的列表或元组。这允许只用索引扫描,用于只选择包含的字段(include)和只通过索引字段过滤(expressions)的查询。
include is supported for GiST and SP-GiST indexes.
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,它为 range boundaries 提供了一个表达式映射。例如:
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),
),
]
8月 05, 2026