PostgreSQL 特有模型字段

所有这些字段都可以从 django.contrib.postgres.field 模块中获得。

对这些字段进行索引

IndexField.db_index 都创建了一个 B 树索引,在查询复杂的数据类型时并不是特别有用。像 GinIndexGistIndex 这样的索引比较适合,不过索引的选择取决于你使用的查询。一般来说,GiST 可能是 range 字段HStoreField 的好选择,而 GIN 可能对 ArrayField 有帮助。

ArrayField

class ArrayField(base_field, size=None, **options)

一个用于存储数据列表的字段。大多数字段类型都可以使用,你可以通过另一个字段实例作为 base_field。你也可以指定一个 sizeArrayField 可以嵌套来存储多维数组。

如果你给字段一个 default,确保它是一个可调用对象,比如 list (对于一个空的默认值),或者一个返回一个列表的可调用对象(比如一个函数)。错误地使用 default=[] 会创建一个可变的默认值,这个默认值在 ArrayField 的所有实例之间共享。

  • base_field

    这是一个必要的参数。

    指定数组的底层数据类型和行为。它应该是 Field 子类的实例。例如,它可以是一个 IntegerField 或一个 CharField。大多数字段类型都是允许的,但不包括处理关系数据的字段(ForeignKeyOneToOneFieldManyToManyField)以及文件字段(FileFieldImageField)。

    可以嵌套数组字段——你可以指定一个 ArrayField 的实例作为 base_field。例如:

    ``` from django.contrib.postgres.fields import ArrayField from django.db import models

  1. class ChessBoard(models.Model):
  2. board = ArrayField(
  3. ArrayField(
  4. models.CharField(max_length=10, blank=True),
  5. size=8,
  6. ),
  7. size=8,
  8. )
  9. ```
  10. 数据库和模型之间的值的转换、数据和配置的验证以及序列化都是委托给底层基础字段的。
  • size

    这是一个可选的参数。

    如果传入,数组将有一个指定的最大大小。这将被传递给数据库,尽管 PostgreSQL 目前并没有强制执行这个限制。

备注

嵌套 ArrayField 时,无论是否使用 size 参数,PostgreSQL 都要求数组为矩形:

  1. from django.contrib.postgres.fields import ArrayField
  2. from django.db import models
  3. class Board(models.Model):
  4. pieces = ArrayField(ArrayField(models.IntegerField()))
  5. # Valid
  6. Board(
  7. pieces=[
  8. [2, 3],
  9. [2, 1],
  10. ]
  11. )
  12. # Not valid
  13. Board(
  14. pieces=[
  15. [2, 3],
  16. [2],
  17. ]
  18. )

如果需要不规则的形状,则应将底层字段设为 null,并将值用 None 填充。

查询 ArrayField

ArrayField 有许多自定义的查找和转换。我们将使用下面的示例模型:

  1. from django.contrib.postgres.fields import ArrayField
  2. from django.db import models
  3. class Post(models.Model):
  4. name = models.CharField(max_length=200)
  5. tags = ArrayField(models.CharField(max_length=200), blank=True)
  6. def __str__(self):
  7. return self.name

contains

ArrayField 上重写了 contains 查询。返回的对象将是那些传递的值是数据的子集的对象。它使用 SQL 运算符 @>。例如:

  1. >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
  2. >>> Post.objects.create(name="Second post", tags=["thoughts"])
  3. >>> Post.objects.create(name="Third post", tags=["tutorial", "django"])
  4. >>> Post.objects.filter(tags__contains=["thoughts"])
  5. <QuerySet [<Post: First post>, <Post: Second post>]>
  6. >>> Post.objects.filter(tags__contains=["django"])
  7. <QuerySet [<Post: First post>, <Post: Third post>]>
  8. >>> Post.objects.filter(tags__contains=["django", "thoughts"])
  9. <QuerySet [<Post: First post>]>

contained_by

这是 contains 查询的反向操作 - 返回的对象将是那些数据是传递的值的子集的对象。它使用 SQL 运算符 <@。例如:

  1. >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
  2. >>> Post.objects.create(name="Second post", tags=["thoughts"])
  3. >>> Post.objects.create(name="Third post", tags=["tutorial", "django"])
  4. >>> Post.objects.filter(tags__contained_by=["thoughts", "django"])
  5. <QuerySet [<Post: First post>, <Post: Second post>]>
  6. >>> Post.objects.filter(tags__contained_by=["thoughts", "django", "tutorial"])
  7. <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>

overlap

返回数据与传递的值共享任何结果的对象。使用 SQL 运算符 &&。例如:

  1. >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
  2. >>> Post.objects.create(name="Second post", tags=["thoughts", "tutorial"])
  3. >>> Post.objects.create(name="Third post", tags=["tutorial", "django"])
  4. >>> Post.objects.filter(tags__overlap=["thoughts"])
  5. <QuerySet [<Post: First post>, <Post: Second post>]>
  6. >>> Post.objects.filter(tags__overlap=["thoughts", "tutorial"])
  7. <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
  8. >>> Post.objects.filter(tags__overlap=Post.objects.values_list("tags"))
  9. <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>

Changed in Django 4.2:

添加了 QuerySet.values()values_list() 作为右操作数的支持。

len

返回数组的长度。之后可用的查询与 IntegerField 相同。例如:

  1. >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
  2. >>> Post.objects.create(name="Second post", tags=["thoughts"])
  3. >>> Post.objects.filter(tags__len=1)
  4. <QuerySet [<Post: Second post>]>

索引转换

Index 转换将索引转换为数组。可以使用任何非负整数。如果超过数组的 size,则不会出现错误。转换后可用的查询是来自 base_field 的查询。例如:

  1. >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
  2. >>> Post.objects.create(name="Second post", tags=["thoughts"])
  3. >>> Post.objects.filter(tags__0="thoughts")
  4. <QuerySet [<Post: First post>, <Post: Second post>]>
  5. >>> Post.objects.filter(tags__1__iexact="Django")
  6. <QuerySet [<Post: First post>]>
  7. >>> Post.objects.filter(tags__276="javascript")
  8. <QuerySet []>

备注

PostgreSQL 在编写原始 SQL 时,对数组字段使用基于 1 的索引。然而这些索引和 slices 中使用的索引使用基于 0 的索引,以与 Python 保持一致。

切片转换

Slice 转换获取数组的一个切片。可以使用两个非负整数,用一个下划线分隔。转换后可用的查询不会改变。例如:

  1. >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
  2. >>> Post.objects.create(name="Second post", tags=["thoughts"])
  3. >>> Post.objects.create(name="Third post", tags=["django", "python", "thoughts"])
  4. >>> Post.objects.filter(tags__0_1=["thoughts"])
  5. <QuerySet [<Post: First post>, <Post: Second post>]>
  6. >>> Post.objects.filter(tags__0_2__contains=["thoughts"])
  7. <QuerySet [<Post: First post>, <Post: Second post>]>

备注

PostgreSQL 在编写原始 SQL 时,对数组字段使用基于 1 的索引。然而这些分片和 indexes 中使用的分片使用基于 0 的索引,以与 Python 保持一致。

带索引和切片的多维数组

PostgreSQL 在多维数组上使用索引和切片时,有一些相当神秘的行为。使用索引向下到达最终的底层数据总是可行的,但是大多数其他的切片在数据库层面的行为很奇怪,不能被 Django 以逻辑的、一致的方式支持。

CIText 字段

class CIText(**options)

4.2 版后已移除.

一个用于创建由 citext 类型支持的不区分大小写的文本字段的混入。在使用它之前,请阅读 性能考虑因素

要使用 citext,使用 CITextExtension ` 操作,在第一次 ``CreateModel` 迁移操作之前,在 PostgreSQL 中 安装 citext 扩展

如果你使用的是 ArrayFieldCIText 字段,你必须在你的 INSTALLED_APPS 中添加 'django.contrib.postgres',否则字段值会以字符串形式出现,比如 '{thoughts,django}'

提供了几个使用混入的字段:

class CICharField(**options)

4.2 版后已移除: CICharField 已被弃用,推荐使用 CharField(db_collation="…") 并使用不区分大小写的非确定性排序规则。

class CIEmailField(**options)

4.2 版后已移除: CIEmailField 已被弃用,推荐使用 EmailField(db_collation="…") 并使用不区分大小写的非确定性排序规则。

class CITextField(**options)

4.2 版后已移除: CITextField 已被弃用,推荐使用 TextField(db_collation="…") 并使用不区分大小写的非确定性排序规则。

这些字段分别是 CharFieldEmailFieldTextField 的子类。

max_length 不会在数据库中强制执行,因为 citext 与 PostgreSQL 的 text 类型相似。

不区分大小写的字节序

最好使用非确定性排序规则而不是 citext 扩展。您可以使用 CreateCollation 迁移操作来创建它们。有关更多详细信息,请参阅 使用迁移来管理整理 和 PostgreSQL 文档中关于 非确定性排序规则 的部分。

HStoreField

class HStoreField(**options)

一个用于存储键值对的字段。使用的 Python 数据类型是 dict。键必须是字符串,值可以是字符串或空值(Python 中的 None)。

要使用该字段,你需要:

  1. 在你的 INSTALLED_APPS 中增加 'django.contrib.postgres'
  2. 在 PostgreSQL 中 安装 hstore 扩展

如果你跳过第一步,你会看到一个错误,比如 can't adapt type 'dict',如果你跳过第二步,你会看到 type "hstore" does not exist

备注

在某些情况下,可能需要要求或限制对某个字段有效的键。这可以使用 KeysValidator 来完成。

查询 HStoreField

除了按键查询的功能外,HStoreField 还有一些自定义查询功能。

我们将使用以下示例模型:

  1. from django.contrib.postgres.fields import HStoreField
  2. from django.db import models
  3. class Dog(models.Model):
  4. name = models.CharField(max_length=200)
  5. data = HStoreField()
  6. def __str__(self):
  7. return self.name

键查找

要根据给定的键查询,您可以将该键用作查找名称:

  1. >>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
  2. >>> Dog.objects.create(name="Meg", data={"breed": "collie"})
  3. >>> Dog.objects.filter(data__breed="collie")
  4. <QuerySet [<Dog: Meg>]>

您可以在键查找后链接其他查询:

  1. >>> Dog.objects.filter(data__breed__contains="l")
  2. <QuerySet [<Dog: Rufus>, <Dog: Meg>]>

或者使用 F() 表达式来注释一个键值。例如:

  1. >>> from django.db.models import F
  2. >>> rufus = Dog.objects.annotate(breed=F("data__breed"))[0]
  3. >>> rufus.breed
  4. 'labrador'

如果你想查询的键与另一个查找的名称冲突,你需要使用 hstorefield.contains 查找来代替。

备注

关键词转换也可以与以下链式进行: containsicontainsendswithiendswithiexactregexiregexstartswithistartswith 查询。

警告

由于任何字符串都可能是 hstore 值中的一个键,因此除了下面列出的以外的任何查询都将被解释为键查询。不会出现任何错误。要格外小心输入错误,并始终检查你的查询是否按照你的意图工作。

contains

HStoreField 上重写了 contains 查询。返回的对象是那些给定的键值对字典都包含在字段中的对象。它使用 SQL 运算符 @>。例如:

  1. >>> Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
  2. >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
  3. >>> Dog.objects.create(name="Fred", data={})
  4. >>> Dog.objects.filter(data__contains={"owner": "Bob"})
  5. <QuerySet [<Dog: Rufus>, <Dog: Meg>]>
  6. >>> Dog.objects.filter(data__contains={"breed": "collie"})
  7. <QuerySet [<Dog: Meg>]>

contained_by

这是 contains 查询的反向操作 - 返回的对象将是那些对象的键值对是传递值中的子集。它使用 SQL 运算符 <@。例如:

  1. >>> Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
  2. >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
  3. >>> Dog.objects.create(name="Fred", data={})
  4. >>> Dog.objects.filter(data__contained_by={"breed": "collie", "owner": "Bob"})
  5. <QuerySet [<Dog: Meg>, <Dog: Fred>]>
  6. >>> Dog.objects.filter(data__contained_by={"breed": "collie"})
  7. <QuerySet [<Dog: Fred>]>

has_key

返回包含给定键的数据的对象。使用 SQL 运算符 ?。例如:

  1. >>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
  2. >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
  3. >>> Dog.objects.filter(data__has_key="owner")
  4. <QuerySet [<Dog: Meg>]>

has_any_keys

返回其中任何给定键存在于数据中的对象。使用 SQL 运算符 ?|。例如:

  1. >>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
  2. >>> Dog.objects.create(name="Meg", data={"owner": "Bob"})
  3. >>> Dog.objects.create(name="Fred", data={})
  4. >>> Dog.objects.filter(data__has_any_keys=["owner", "breed"])
  5. <QuerySet [<Dog: Rufus>, <Dog: Meg>]>

has_keys

返回其中所有给定键都存在于数据中的对象。使用 SQL 运算符 ?&。例如:

  1. >>> Dog.objects.create(name="Rufus", data={})
  2. >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
  3. >>> Dog.objects.filter(data__has_keys=["breed", "owner"])
  4. <QuerySet [<Dog: Meg>]>

keys

返回键数组与给定值相等的对象。请注意,顺序不能保证可靠,因此此转换主要用于与 ArrayField 上的查找一起使用。使用 SQL 函数 akeys()。例如:

  1. >>> Dog.objects.create(name="Rufus", data={"toy": "bone"})
  2. >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
  3. >>> Dog.objects.filter(data__keys__overlap=["breed", "toy"])
  4. <QuerySet [<Dog: Rufus>, <Dog: Meg>]>

values

返回值数组与给定值相等的对象。请注意,顺序不能保证可靠,因此此转换主要用于与 ArrayField 上的查找一起使用。使用 SQL 函数 avals()。例如:

  1. >>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
  2. >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
  3. >>> Dog.objects.filter(data__values__contains=["collie"])
  4. <QuerySet [<Dog: Meg>]>

范围字段

有五种范围字段类型,对应 PostgreSQL 中内置的范围类型。这些字段用来存储一个范围的值,例如一个事件的开始和结束时间戳,或者一个活动适合的年龄范围。

所有的范围字段在 Python 中都会翻译成 psycopg Range 对象,但如果不需要边界信息,也可以接受元组作为输入。默认是包含下界,不包含上界,即 [) (有关 不同边界 的详细信息,请参阅 PostgreSQL 文档)。对于非离散范围字段(例如 DateTimeRangeFieldDecimalRangeField),可以使用 default_bounds 参数更改默认边界。

IntegerRangeField

class IntegerRangeField(**options)

存储一组整数范围。基于 IntegerField。在数据库中由 int4range 表示,在 Python 中由 django.db.backends.postgresql.psycopg_any.NumericRange 表示。

无论在保存数据时指定的边界是什么,PostgreSQL 总是以规范的形式返回一个包括下限和排除上限的范围,即 [)

BigIntegerRangeField

class BigIntegerRangeField(**options)

存储一组大整数范围。基于 BigIntegerField。在数据库中由 int8range 表示,在 Python 中由 django.db.backends.postgresql.psycopg_any.NumericRange 表示。

无论在保存数据时指定的边界是什么,PostgreSQL 总是以规范的形式返回一个包括下限和排除上限的范围,即 [)

DecimalRangeField

class DecimalRangeField(default_bounds=’[)’, **options)

存储一组浮点数值范围。基于 DecimalField。在数据库中由 numrange 表示,在 Python 中由 django.db.backends.postgresql.psycopg_any.NumericRange 表示。

  • default_bounds

    New in Django 4.1.

    可选。列表和元组输入的 bounds 值。默认为包含下界,不包含上界,即 [) (有关 不同边界 的详细信息,请参阅 PostgreSQL 文档)。default_bounds 不用于 django.db.backends.postgresql.psycopg_any.NumericRange 输入。

DateTimeRangeField

class DateTimeRangeField(default_bounds=’[)’, **options)

存储一组时间戳范围。基于 DateTimeField。在数据库中由 tstzrange 表示,在 Python 中由 django.db.backends.postgresql.psycopg_any.DateTimeTZRange 表示。

  • default_bounds

    New in Django 4.1.

    可选。列表和元组输入的 bounds 值。默认为包含下界,不包含上界,即 [) (有关 不同边界 的详细信息,请参阅 PostgreSQL 文档)。default_bounds 不用于 django.db.backends.postgresql.psycopg_any.DateTimeTZRange 输入。

DateRangeField

class DateRangeField(**options)

存储一组日期范围。基于 DateField。在数据库中由 daterange 表示,在 Python 中由 django.db.backends.postgresql.psycopg_any.DateRange 表示。

无论在保存数据时指定的边界是什么,PostgreSQL 总是以规范的形式返回一个包括下限和排除上限的范围,即 [)

查询范围字段

对于范围字段,有许多自定义查找和转换。它们适用于所有上述字段,但我们将使用以下示例模型:

  1. from django.contrib.postgres.fields import IntegerRangeField
  2. from django.db import models
  3. class Event(models.Model):
  4. name = models.CharField(max_length=200)
  5. ages = IntegerRangeField()
  6. start = models.DateTimeField()
  7. def __str__(self):
  8. return self.name

我们还将使用以下示例对象:

  1. >>> import datetime
  2. >>> from django.utils import timezone
  3. >>> now = timezone.now()
  4. >>> Event.objects.create(name="Soft play", ages=(0, 10), start=now)
  5. >>> Event.objects.create(
  6. ... name="Pub trip", ages=(21, None), start=now - datetime.timedelta(days=1)
  7. ... )

NumericRange

  1. >>> from django.db.backends.postgresql.psycopg_any import NumericRange

包含函数

与其他 PostgreSQL 字段一样,有三个标准的包含运算符。containscontained_byoverlap,分别使用 SQL 运算符 @><@&&

contains
  1. >>> Event.objects.filter(ages__contains=NumericRange(4, 5))
  2. <QuerySet [<Event: Soft play>]>
contained_by
  1. >>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
  2. <QuerySet [<Event: Soft play>]>

contained_by 查询也适用于非范围字段类型: SmallAutoField, AutoField, BigAutoField, SmallIntegerField, IntegerField, BigIntegerField, DecimalField, FloatField, DateField, 和 DateTimeField。例如:

  1. >>> from django.db.backends.postgresql.psycopg_any import DateTimeTZRange
  2. >>> Event.objects.filter(
  3. ... start__contained_by=DateTimeTZRange(
  4. ... timezone.now() - datetime.timedelta(hours=1),
  5. ... timezone.now() + datetime.timedelta(hours=1),
  6. ... ),
  7. ... )
  8. <QuerySet [<Event: Soft play>]>
overlap
  1. >>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
  2. <QuerySet [<Event: Soft play>]>

比较函数

范围字段支持标准查询:ltgtltegte。这些并没有特别大的帮助——它们先比较下界,然后在必要时才比较上界。这也是用于按范围字段排序的策略。最好是使用特定的范围比较运算符。

fully_lt

返回的范围严格小于传入的范围。换句话说,返回范围内的所有点都小于传入范围内的所有点。

  1. >>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15))
  2. <QuerySet [<Event: Soft play>]>
fully_gt

返回的范围严格大于传入的范围。换句话说,返回范围内的所有点都大于传入范围内的所有点。

  1. >>> Event.objects.filter(ages__fully_gt=NumericRange(11, 15))
  2. <QuerySet [<Event: Pub trip>]>
not_lt

返回的范围不包含任何小于传入范围的点,即返回范围的下界至少是传入范围的下界。

  1. >>> Event.objects.filter(ages__not_lt=NumericRange(0, 15))
  2. <QuerySet [<Event: Soft play>, <Event: Pub trip>]>
not_gt

返回的范围不包含任何大于传入范围的点,也就是说,返回的范围的上界最多就是传入范围的上界。

  1. >>> Event.objects.filter(ages__not_gt=NumericRange(3, 10))
  2. <QuerySet [<Event: Soft play>]>
adjacent_to

返回的范围与传入的范围共享一个边界。

  1. >>> Event.objects.filter(ages__adjacent_to=NumericRange(10, 21))
  2. <QuerySet [<Event: Soft play>, <Event: Pub trip>]>

使用边界进行查询

范围字段支持几个额外的查找。

startswith

返回的对象具有给定的下界。可以链入基础字段的有效查找。

  1. >>> Event.objects.filter(ages__startswith=21)
  2. <QuerySet [<Event: Pub trip>]>
endswith

返回的对象具有给定的上界。可以链入基础字段的有效查找。

  1. >>> Event.objects.filter(ages__endswith=10)
  2. <QuerySet [<Event: Soft play>]>
isempty

返回的对象是空的范围。可以链到有效的查找 BooleanField

  1. >>> Event.objects.filter(ages__isempty=True)
  2. <QuerySet []>
lower_inc

根据传递的布尔值,返回具有包含或不包含下界的对象。可以链到有效的查找 BooleanField 的对象。

  1. >>> Event.objects.filter(ages__lower_inc=True)
  2. <QuerySet [<Event: Soft play>, <Event: Pub trip>]>
lower_inf

根据传递的布尔值,返回具有无界(无限)或仅有下界的对象。可以链到有效的查找 BooleanField

  1. >>> Event.objects.filter(ages__lower_inf=True)
  2. <QuerySet []>
upper_inc

根据传递的布尔值,返回具有包含或不包含上界的对象。可以链到有效的查找 BooleanField 的对象。

  1. >>> Event.objects.filter(ages__upper_inc=True)
  2. <QuerySet []>
upper_inf

根据传递的布尔值,返回具有无界(无限)或仅有上界的对象。可以链到有效的查找 BooleanField

  1. >>> Event.objects.filter(ages__upper_inf=True)
  2. <QuerySet [<Event: Pub trip>]>

定义自己的范围类型

PostgreSQL 允许定义自定义范围类型。Django 的模型和表单字段实现使用以下基类,并且 psycopg 提供了一个 register_range() 函数来允许使用自定义范围类型。

class RangeField(**options)

模型范围字段的基类。

class django.contrib.postgres.forms.BaseRangeField

表范围字段的基类。

  • base_field

    要使用的表字段。

  • range_type

    要使用的范围类型。

范围操作

class RangeOperators

PostgreSQL 提供了一组 SQL 运算符,这些运算符可以和范围数据类型一起使用(参见 `the PostgreSQL documentation for the full details of range operators `_ )。这个类的目的是作为一种方便的方法,以避免排版错误。运算符名称与相应的查找名称重叠。

  1. class RangeOperators:
  2. EQUAL = "="
  3. NOT_EQUAL = "<>"
  4. CONTAINS = "@>"
  5. CONTAINED_BY = "<@"
  6. OVERLAPS = "&&"
  7. FULLY_LT = "<<"
  8. FULLY_GT = ">>"
  9. NOT_LT = "&>"
  10. NOT_GT = "&<"
  11. ADJACENT_TO = "-|-"

RangeBoundary() 表达式

class RangeBoundary(inclusive_lower=True, inclusive_upper=False)

  • inclusive_lower

    如果 True (默认),则下界为包含 '[',否则为不包含 '('

  • inclusive_upper

    如果 False (默认),则上界为包含 ')',否则为不包含 ']'

RangeBoundary() 表达式表示范围边界。它可以与自定义的范围函数一起使用,预期边界,例如定义 ExclusionConstraint。参见 `the PostgreSQL documentation for the full details `_ 。