Ограничения базы данных, специфичные для PostgreSQL ¶
PostgreSQL поддерживает дополнительные ограничения целостности данных, доступные из
django.contrib.postgres.constraints
модуля. Они добавлены в Meta.constraints
вариант модели
.
ExclusionConstraint
¶
-
class
ExclusionConstraint
( * , имя , выражения , index_type = None , condition = None , deferrable = None , include = None , opclasses = () ) ¶ Создает ограничение исключения в базе данных. Внутренне PostgreSQL реализует ограничения исключения с помощью индексов. Тип индекса по умолчанию - GiST . Чтобы использовать их, вам необходимо активировать расширение btree_gist в PostgreSQL. Вы можете установить его с помощью
BtreeGistExtension
операции миграции.Если вы пытаетесь вставить новую строку, которая конфликтует с существующей строкой, возникает
IntegrityError
. Точно так же, когда обновление конфликтует с существующей строкой.
expressions
¶
-
ExclusionConstraint.
expressions
¶
Итерация двух кортежей. Первый элемент - это выражение или строка. Второй элемент - это оператор SQL, представленный в виде строки. Чтобы избежать опечаток, вы можете использовать RangeOperators
which сопоставляет операторы со строками. Например:
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
¶
Установите этот параметр, чтобы создать отложенное ограничение исключения. Допустимые значения: 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 12+.
opclasses
¶
-
ExclusionConstraint.
opclasses
¶
Имена классов операторов PostgreSQL, используемых для этого ограничения. Если вам требуется настраиваемый класс операторов, вы должны предоставить по одному для каждого выражения в ограничении.
Например:
ExclusionConstraint(
name='exclude_overlapping_opclasses',
expressions=[('circle', RangeOperators.OVERLAPS)],
opclasses=['circle_ops'],
)
создает ограничение исключения при circle
использовании circle_ops
.
Примеры ¶
В следующем примере ограничиваются перекрывающиеся бронирования в одной комнате без учета отмененных бронирований:
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),
),
]