========================================PostgreSQL specific database constraints========================================.. module:: django.contrib.postgres.constraints:synopsis: PostgreSQL specific database constraintPostgreSQL supports additional data integrity constraints available from the``django.contrib.postgres.constraints`` module. They are added in the model:attr:`Meta.constraints <django.db.models.Options.constraints>` option.``ExclusionConstraint``=======================.. class:: ExclusionConstraint(*, name, expressions, index_type=None, condition=None, deferrable=None, include=None, opclasses=(), violation_error_message=None)Creates an exclusion constraint in the database. Internally, PostgreSQLimplements exclusion constraints using indexes. The default index type is`GiST <https://www.postgresql.org/docs/current/gist.html>`_. To use them,you need to activate the `btree_gist extension<https://www.postgresql.org/docs/current/btree-gist.html>`_ on PostgreSQL.You can install it using the:class:`~django.contrib.postgres.operations.BtreeGistExtension` migrationoperation.If you attempt to insert a new row that conflicts with an existing row, an:exc:`~django.db.IntegrityError` is raised. Similarly, when updateconflicts with an existing row.Exclusion constraints are checked during the :ref:`model validation<validating-objects>`... versionchanged:: 4.1In older versions, exclusion constraints were not checked during modelvalidation.``name``--------.. attribute:: ExclusionConstraint.nameSee :attr:`.BaseConstraint.name`.``expressions``---------------.. attribute:: ExclusionConstraint.expressionsAn iterable of 2-tuples. The first element is an expression or string. Thesecond element is an SQL operator represented as a string. To avoid typos, youmay use :class:`~django.contrib.postgres.fields.RangeOperators` which maps theoperators with strings. For example::expressions=[('timespan', RangeOperators.ADJACENT_TO),(F('room'), RangeOperators.EQUAL),].. admonition:: Restrictions on operators.Only commutative operators can be used in exclusion constraints.The :class:`OpClass() <django.contrib.postgres.indexes.OpClass>` expression canbe used to specify a custom `operator class`_ for the constraint expressions.For example::expressions=[(OpClass('circle', name='circle_ops'), RangeOperators.OVERLAPS),]creates an exclusion constraint on ``circle`` using ``circle_ops``... versionchanged:: 4.1Support for the ``OpClass()`` expression was added... _operator class: https://www.postgresql.org/docs/current/indexes-opclass.html``index_type``--------------.. attribute:: ExclusionConstraint.index_typeThe index type of the constraint. Accepted values are ``GIST`` or ``SPGIST``.Matching is case insensitive. If not provided, the default index type is``GIST``.``condition``-------------.. attribute:: ExclusionConstraint.conditionA :class:`~django.db.models.Q` object that specifies the condition to restricta constraint to a subset of rows. For example,``condition=Q(cancelled=False)``.These conditions have the same database restrictions as:attr:`django.db.models.Index.condition`.``deferrable``--------------.. attribute:: ExclusionConstraint.deferrableSet this parameter to create a deferrable exclusion constraint. Accepted valuesare ``Deferrable.DEFERRED`` or ``Deferrable.IMMEDIATE``. For example::from django.contrib.postgres.constraints import ExclusionConstraintfrom django.contrib.postgres.fields import RangeOperatorsfrom django.db.models import DeferrableExclusionConstraint(name='exclude_overlapping_deferred',expressions=[('timespan', RangeOperators.OVERLAPS),],deferrable=Deferrable.DEFERRED,)By default constraints are not deferred. A deferred constraint will not beenforced until the end of the transaction. An immediate constraint will beenforced immediately after every command... warning::Deferred exclusion constraints may lead to a `performance penalty<https://www.postgresql.org/docs/current/sql-createtable.html#id-1.9.3.85.9.4>`_.``include``-----------.. attribute:: ExclusionConstraint.includeA list or tuple of the names of the fields to be included in the coveringexclusion constraint as non-key columns. This allows index-only scans to beused for queries that select only included fields(:attr:`~ExclusionConstraint.include`) and filter only by indexed fields(:attr:`~ExclusionConstraint.expressions`).``include`` is supported for GiST indexes on PostgreSQL 12+ and SP-GiSTindexes on PostgreSQL 14+... versionchanged:: 4.1Support for covering exclusion constraints using SP-GiST indexes onPostgreSQL 14+ was added.``opclasses``-------------.. attribute:: ExclusionConstraint.opclassesThe names of the `PostgreSQL operator classes<https://www.postgresql.org/docs/current/indexes-opclass.html>`_ to use forthis constraint. If you require a custom operator class, you must provide onefor each expression in the constraint.For example::ExclusionConstraint(name='exclude_overlapping_opclasses',expressions=[('circle', RangeOperators.OVERLAPS)],opclasses=['circle_ops'],)creates an exclusion constraint on ``circle`` using ``circle_ops``... deprecated:: 4.1The ``opclasses`` parameter is deprecated in favor of using:class:`OpClass() <django.contrib.postgres.indexes.OpClass>` in:attr:`~ExclusionConstraint.expressions`.``violation_error_message``---------------------------.. versionadded:: 4.1The error message used when ``ValidationError`` is raised during:ref:`model validation <validating-objects>`. Defaults to:attr:`.BaseConstraint.violation_error_message`.Examples--------The following example restricts overlapping reservations in the same room, nottaking canceled reservations into account::from django.contrib.postgres.constraints import ExclusionConstraintfrom django.contrib.postgres.fields import DateTimeRangeField, RangeOperatorsfrom django.db import modelsfrom django.db.models import Qclass 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),),]In case your model defines a range using two fields, instead of the nativePostgreSQL range types, you should write an expression that uses the equivalentfunction (e.g. ``TsTzRange()``), and use the delimiters for the field. Mostoften, the delimiters will be ``'[)'``, meaning that the lower bound isinclusive and the upper bound is exclusive. You may use the:class:`~django.contrib.postgres.fields.RangeBoundary` that provides anexpression mapping for the `range boundaries <https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-INCLUSIVITY>`_. For example::from django.contrib.postgres.constraints import ExclusionConstraintfrom django.contrib.postgres.fields import (DateTimeRangeField,RangeBoundary,RangeOperators,)from django.db import modelsfrom django.db.models import Func, Qclass 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),),]