PostgreSQL 特定的数据库约束 — Django 文档
PostgreSQL 特定的数据库约束
PostgreSQL 支持来自 django.contrib.postgres.constraints
模块的额外数据完整性约束。 它们被添加到模型 Meta.constraints 选项中。
ExclusionConstraint
3.0 版中的新功能。
- class ExclusionConstraint(*, name, expressions, index_type=None, condition=None, deferrable=None)
在数据库中创建排除约束。 在内部,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),
]
对运营商的限制。
在排除约束中只能使用交换运算符。
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,
)
默认情况下不延迟约束。 在事务结束之前不会强制执行延迟约束。 立即约束将在每个命令后立即强制执行。
例子
以下示例限制同一房间内的重叠预订,不考虑取消的预订:
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),
),
]