PostgreSQL 支持额外的数据完整性约束,可从 django.contrib.postgres.cracks
模块中获得。它们被添加到模型 Meta.constraints
选项中。
ExclusionConstraint
¶ExclusionConstraint
(*, name, expressions, index_type=None, condition=None, deferrable=None, include=None, opclasses=(), violation_error_message=None)¶在数据库中创建一个排除约束。在内部,PostgreSQL 使用索引来实现排除约束的功能。默认的索引类型是 GiST 。要使用它们,你需要激活 PostgreSQL 上的 btree_gist 扩展 。你可以使用 BtreeGistExtension
迁移操作来安装它。
如果你试图插入一条新的记录,而这条记录与现有的记录发生冲突,就会引发一个 IntegrityError
。同样,当更新与现有的记录冲突时,也会发出 IntegrityError
。
Exclusion constraints are checked during the model validation.
In older versions, exclusion constraints were not checked during model validation.
expressions
¶ExclusionConstraint.
expressions
¶一个二元元组的迭代。第一个元素是一个表达式或字符串。第二个元素是一个用字符串表示的 SQL 操作符。为了避免错别字,你可以使用 RangeOperators
将操作符与字符串进行映射。例如:
expressions = [
("timespan", RangeOperators.ADJACENT_TO),
(F("room"), RangeOperators.EQUAL),
]
对操作的限制。
只有交换运算符才能用于排除约束。
The OpClass()
expression can
be used to specify a custom operator class for the constraint expressions.
For example:
expressions = [
(OpClass("circle", name="circle_ops"), RangeOperators.OVERLAPS),
]
使用 circle_ops
在 circle
上创建一个排除约束。
Support for the OpClass()
expression was added.
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
is supported for GiST indexes. PostgreSQL 14+ also supports
include
for SP-GiST indexes.
Support for covering exclusion constraints using SP-GiST indexes on PostgreSQL 14+ was added.
opclasses
¶ExclusionConstraint.
opclasses
¶用于此约束的 PostgreSQL 运算符类的名称 。如果你需要一个自定义的运算符类,你必须为约束中的每个表达式提供一个。
例子:
ExclusionConstraint(
name="exclude_overlapping_opclasses",
expressions=[("circle", RangeOperators.OVERLAPS)],
opclasses=["circle_ops"],
)
使用 circle_ops
在 circle
上创建一个排除约束。
4.1 版后已移除: The opclasses
parameter is deprecated in favor of using
OpClass()
in
expressions
.
violation_error_message
¶The error message used when ValidationError
is raised during
model validation. Defaults to
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),
),
]
5月 12, 2023