Специфичные для 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)[исходный код] -
Создаёт в базе данных ограничение исключения. Внутри PostgreSQL реализует ограничения исключения с помощью индексов. Тип индекса по умолчанию — GiST. Для их использования необходимо активировать в PostgreSQL расширение btree_gist. Его можно установить с помощью операции миграции
BtreeGistExtension.При попытке вставить новую строку, конфликтующую с существующей, возникает исключение
IntegrityError. То же происходит, если обновление конфликтует с существующей строкой.Ограничения исключения проверяются во время проверки модели.
name
-
ExclusionConstraint.name
См. BaseConstraint.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).
include поддерживается для индексов GiST. PostgreSQL 14+ также поддерживает include для индексов SP-GiST.
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),
),
]
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/ref/contrib/postgres/constraints/