PostgreSQL 特定的数据库约束 — Django 文档

来自菜鸟教程
Django/docs/3.1.x/ref/contrib/postgres/constraints
跳转至:导航、​搜索

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

约束的索引类型。 可接受的值为 GISTSPGIST。 匹配不区分大小写。 如果未提供,则默认索引类型为 GIST


condition

ExclusionConstraint.condition

一个 Q 对象,它指定将约束限制为行子集的条件。 例如,condition=Q(cancelled=False)

这些条件与 django.db.models.Index.condition 具有相同的数据库限制。


deferrable

ExclusionConstraint.deferrable

3.1 版中的新功能。


设置此参数以创建可延迟排除约束。 可接受的值为 Deferrable.DEFERREDDeferrable.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),
            ),
        ]