Ограничения базы данных, специфичные для PostgreSQL
PostgreSQL поддерживает дополнительные ограничения целостности данных, доступные из модуля django.contrib.postgres.constraints. Они добавляются в опцию модели Meta.constraints.
ExclusionConstraint
-
class ExclusionConstraint(*, name, expressions, index_type=None, condition=None, deferrable=None) -
Создаёт ограничение исключения в базе данных. Внутренне PostgreSQL реализует ограничения исключения с использованием индексов. Тип индекса по умолчанию — GiST. Для их использования необходимо активировать расширение btree_gist в PostgreSQL. Его можно установить с помощью операции миграции
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
Установите этот параметр для создания откладываемого ограничения исключения. Допустимые значения — 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),
),
]
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.1/ref/contrib/postgres/constraints/