# Django 3.2.11.dev 文档

# PostgreSQL 特有模型字段

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

## 对这些字段进行索引

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

## `ArrayField`

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

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

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

  `base_field`

    这是一个必要的参数。

    指定数组的基础数据类型和行为。它应该是 `Field` 的一个子类的实例。例如，它可以是一个 `IntegerField` 或一个 `CharField`。除了那些处理关系型数据的字段（`ForeignKey`、`OneToOneField` 和 `ManyToManyField`）之外，大多数字段类型都是允许的。

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

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

        class ChessBoard(models.Model):
            board = ArrayField(
                ArrayField(
                    models.CharField(max_length=10, blank=True),
                    size=8,
                ),
                size=8,
            )

    数据库和模型之间的值的转换、数据和配置的验证以及序列化都是委托给底层基础字段的。

  `size`

    这是一个可选的参数。

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

注解

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

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

    class Board(models.Model):
        pieces = ArrayField(ArrayField(models.IntegerField()))

    # Valid
    Board(pieces=[
        [2, 3],
        [2, 1],
    ])

    # Not valid
    Board(pieces=[
        [2, 3],
        [2],
    ])

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

### 查询 `ArrayField`

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

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

    class Post(models.Model):
        name = models.CharField(max_length=200)
        tags = ArrayField(models.CharField(max_length=200), blank=True)

        def __str__(self):
            return self.name

#### `contains`

`contains` 查找在 `ArrayField` 上被覆盖。返回的对象将是那些传入值子集的数据。它使用 SQL 运算符 `@>`。例如：

    >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
    >>> Post.objects.create(name='Second post', tags=['thoughts'])
    >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])

    >>> Post.objects.filter(tags__contains=['thoughts'])
    <QuerySet [<Post: First post>, <Post: Second post>]>

    >>> Post.objects.filter(tags__contains=['django'])
    <QuerySet [<Post: First post>, <Post: Third post>]>

    >>> Post.objects.filter(tags__contains=['django', 'thoughts'])
    <QuerySet [<Post: First post>]>

#### `contained_by`

这是 `contains` 查找的反义词——返回的对象将是那些传入值子集的数据。它使用 SQL 运算符 `<@``。例如：

    >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
    >>> Post.objects.create(name='Second post', tags=['thoughts'])
    >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])

    >>> Post.objects.filter(tags__contained_by=['thoughts', 'django'])
    <QuerySet [<Post: First post>, <Post: Second post>]>

    >>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial'])
    <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>

#### `overlap`

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

    >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
    >>> Post.objects.create(name='Second post', tags=['thoughts'])
    >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])

    >>> Post.objects.filter(tags__overlap=['thoughts'])
    <QuerySet [<Post: First post>, <Post: Second post>]>

    >>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
    <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>

#### `len`

返回数组的长度。之后可用的查找是 `IntegerField` 的查找。例如：

    >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
    >>> Post.objects.create(name='Second post', tags=['thoughts'])

    >>> Post.objects.filter(tags__len=1)
    <QuerySet [<Post: Second post>]>

#### 索引转换

索引转换将索引转化为数组。可以使用任何非负的整数。如果超过数组的 `size`，则不会出错。变换后可用的查找是来自 `base_field` 的查找。例如：

    >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
    >>> Post.objects.create(name='Second post', tags=['thoughts'])

    >>> Post.objects.filter(tags__0='thoughts')
    <QuerySet [<Post: First post>, <Post: Second post>]>

    >>> Post.objects.filter(tags__1__iexact='Django')
    <QuerySet [<Post: First post>]>

    >>> Post.objects.filter(tags__276='javascript')
    <QuerySet []>

注解

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

#### 切片转换

切片转换取数组的一个切片。可以使用任何两个非负的整数，用一个下划线分开。变换后的查找结果不会改变。例如：

    >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
    >>> Post.objects.create(name='Second post', tags=['thoughts'])
    >>> Post.objects.create(name='Third post', tags=['django', 'python', 'thoughts'])

    >>> Post.objects.filter(tags__0_1=['thoughts'])
    <QuerySet [<Post: First post>, <Post: Second post>]>

    >>> Post.objects.filter(tags__0_2__contains=['thoughts'])
    <QuerySet [<Post: First post>, <Post: Second post>]>

注解

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

带索引和切片的多维数组

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

## `CIText` 字段

class `CIText`(**options)

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

  要使用 `citext`，在第一次 `CreateModel` 迁移操作之前，使用 `CITextExtension` 操作 在PostgreSQL 中设置 citext 扩展。

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

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

class `CICharField`(**options)

class `CIEmailField`(**options)

class `CITextField`(**options)

  这些字段分别是 `CharField`、`EmailField` 和 `TextField` 的子类。

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

不区分大小写的字节序

在 PostgreSQL 12+ 上，最好使用非确定的字节序，而不是 `citext` 扩展。你可以使用 `CreateCollation` 迁移操作来创建它们。更多细节，请参阅 使用迁移来管理整理 和 PostgreSQL 关于`non-deterministic collations`_ 的文档。

## `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` 还有一些自定义查询功能。

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

    from django.contrib.postgres.fields import HStoreField
    from django.db import models

    class Dog(models.Model):
        name = models.CharField(max_length=200)
        data = HStoreField()

        def __str__(self):
            return self.name

#### 键查找

要根据给定的键进行查询，可以使用该键作为查询名：

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie'})

    >>> Dog.objects.filter(data__breed='collie')
    <QuerySet [<Dog: Meg>]>

你可以在键查询后链式查询：

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

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

注解

Key transforms can also be chained with: `contains`, `icontains`, `endswith`, `iendswith`, `iexact`, `regex`, `iregex`, `startswith`, and `istartswith` lookups.

警告

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

#### `contains`

`contains` 查找在 `HStoreField` 上被覆盖。返回的对象是那些给定的 `dict` 的键值对都包含在字段中的对象。它使用 SQL 运算符 `@>`。例如：

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
    >>> Dog.objects.create(name='Fred', data={})

    >>> Dog.objects.filter(data__contains={'owner': 'Bob'})
    <QuerySet [<Dog: Rufus>, <Dog: Meg>]>

    >>> Dog.objects.filter(data__contains={'breed': 'collie'})
    <QuerySet [<Dog: Meg>]>

#### `contained_by`

这是 `contains` 查找的反义词——返回的对象将是那些传入值子集对象上的键值对。它使用 SQL 运算符 `<@`。例如：

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
    >>> Dog.objects.create(name='Fred', data={})

    >>> Dog.objects.filter(data__contained_by={'breed': 'collie', 'owner': 'Bob'})
    <QuerySet [<Dog: Meg>, <Dog: Fred>]>

    >>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
    <QuerySet [<Dog: Fred>]>

#### `has_key`

返回数据中给定键所在的对象。使用 SQL 运算符 `?`。例如：

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})

    >>> Dog.objects.filter(data__has_key='owner')
    <QuerySet [<Dog: Meg>]>

#### `has_any_keys`

返回数据中任意给定键的对象。使用 SQL 运算符 `?|`。例如：

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
    >>> Dog.objects.create(name='Meg', data={'owner': 'Bob'})
    >>> Dog.objects.create(name='Fred', data={})

    >>> Dog.objects.filter(data__has_any_keys=['owner', 'breed'])
    <QuerySet [<Dog: Rufus>, <Dog: Meg>]>

#### `has_keys`

返回数据中所有给定键的对象。使用 SQL 运算符 `?&`。例如：

    >>> Dog.objects.create(name='Rufus', data={})
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})

    >>> Dog.objects.filter(data__has_keys=['breed', 'owner'])
    <QuerySet [<Dog: Meg>]>

#### `keys`

返回键数组为给定值的对象。需要注意的是，这个顺序并不能保证可靠，所以这个变换主要是用于与 `ArrayField` 上的查找结合使用。使用 SQL 函数 `akeys()`。例如：

    >>> Dog.objects.create(name='Rufus', data={'toy': 'bone'})
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})

    >>> Dog.objects.filter(data__keys__overlap=['breed', 'toy'])
    <QuerySet [<Dog: Rufus>, <Dog: Meg>]>

#### `values`

返回对象，其中数组的值是给定的值。注意，顺序不保证可靠，所以这个转换主要用于与 `ArrayField` 上的查询结合使用。使用 SQL 函数 `avals()`。例如：

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})

    >>> Dog.objects.filter(data__values__contains=['collie'])
    <QuerySet [<Dog: Meg>]>

## `JSONField`

class `JSONField`(encoder=None, **options)

  一个用于存储 JSON 编码数据的字段。在 Python 中，数据以其 Python 本地格式表示：字典、列表、字符串、数字、布尔值和 `None`。

  `encoder`

    一个可选的 JSON 编码类，用于序列化标准 JSON 序列化器不支持的数据类型（`datetime`、`uuid` 等）。例如，你可以使用 `DjangoJSONEncoder` 类或任何其他 `json.JSONEncoder` 子类。

    当从数据库中获取值时，它将以自定义编码器选择的格式（最常见的是字符串），因此你需要采取额外的步骤将值转换回初始数据类型（`Model.from_db()` 和 `Field.from_db_value()` 是两个可能的钩子）。你的反序列化可能需要考虑到你无法确定输入类型的事实。例如，你有可能返回一个 `datetime`，但实际上是一个字符串，而这个字符串恰好与 `datetime` 的格式相同。

  如果你给字段一个 `default`，确保它是一个可调用对象，比如 `dict` （对于一个空的默认值），或者一个返回字典的可调用对象（比如一个函数）。错误地使用 `default={}` 会创建一个可变的默认值，这个默认值在 `JSONField` 的所有实例之间共享。

注解

PostgreSQL 有两种基于 JSON 的原生数据类型： `json` 和 `jsonb`。`json` 和 `jsonb`。它们之间的主要区别在于它们的存储方式和查询方式。PostgreSQL 的 `json` 字段是作为 JSON 的原始字符串表示来存储的，当根据键来查询时，必须同时进行解码。`jsonb` 字段是基于 JSON 的实际结构存储的，它允许索引。这样做的代价是在写入 `jsonb` 字段时增加了一点成本。`JSONField` 使用 `jsonb`。

3.1 版后已移除: 使用 `django.db.models.JSONField` 代替。

### 查询 `JSONField`

详见 查询 JSONField。

## 范围字段

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

所有的范围字段都翻译成 Python 中的 psycopg2 范围对象，但如果不需要边界信息，也接受元组作为输入。默认是包含下界，排除上界，也就是 `[)` （关于 不同的边界 ），请参见 PostgreSQL 文档。

### `IntegerRangeField`

class `IntegerRangeField`(**options)

  存储一个整数范围。基于一个 `IntegerField`。在数据库中用 `int4range` 表示，在 Python 中用一个 `NumericRange` 表示。

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

### `BigIntegerRangeField`

class `BigIntegerRangeField`(**options)

  存储大整数的范围。基于一个 `BigIntegerField`。在数据库中用 `int8range` 表示，在 Python 中用一个 `NumericRange` 表示。

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

### `DecimalRangeField`

class `DecimalRangeField`(**options)

  存储浮点值的范围。基于 `DecimalField`。在数据库中用 `numrange` 表示，在 Python 中用一个 `NumericRange` 表示。

### `DateTimeRangeField`

class `DateTimeRangeField`(**options)

  存储一系列的时间戳。基于 `DateTimeField`。在数据库中用 `tstzrange` 表示，在 Python 中用一个 `DateTimeTZRange` 表示。

### `DateRangeField`

class `DateRangeField`(**options)

  存储一系列的日期。基于 `DateField`。在数据库中用 `daterange` 表示，在 Python 中用一个 `DateRange` 表示。

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

### 查询范围字段

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

    from django.contrib.postgres.fields import IntegerRangeField
    from django.db import models

    class Event(models.Model):
        name = models.CharField(max_length=200)
        ages = IntegerRangeField()
        start = models.DateTimeField()

        def __str__(self):
            return self.name

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

    >>> import datetime
    >>> from django.utils import timezone
    >>> now = timezone.now()
    >>> Event.objects.create(name='Soft play', ages=(0, 10), start=now)
    >>> Event.objects.create(name='Pub trip', ages=(21, None), start=now - datetime.timedelta(days=1))

和 `NumericRange`：

    >>> from psycopg2.extras import NumericRange

#### 包含函数

与其他 PostgreSQL 字段一样，有三个标准的包含运算符。`contains`、`contained_by` 和 `overlap`，分别使用 SQL 运算符 `@>`、`<@` 和 `&&`。

##### `contains`

    >>> Event.objects.filter(ages__contains=NumericRange(4, 5))
    <QuerySet [<Event: Soft play>]>

##### `contained_by`

    >>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
    <QuerySet [<Event: Soft play>]>

`contained_by` 也可以在非范围字段类型上进行查询： `SmallAutoField`、`AutoField`、`BigAutoField`、`SmallIntegerField`、`IntegerField`、`BigIntegerField`、`DecimalField`、`FloatField`、`DateField` 和 `DateTimeField`。例如：

    >>> from psycopg2.extras import DateTimeTZRange
    >>> Event.objects.filter(
    ...     start__contained_by=DateTimeTZRange(
    ...         timezone.now() - datetime.timedelta(hours=1),
    ...         timezone.now() + datetime.timedelta(hours=1),
    ...     ),
    ... )
    <QuerySet [<Event: Soft play>]>

Changed in Django 3.1:

增加了对 `SmallAutoField`、`AutoField`、`BigAutoField`、`SmallIntegerField` 和 `DecimalField` 的支持。

##### `overlap`

    >>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
    <QuerySet [<Event: Soft play>]>

#### 比较函数

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

##### `fully_lt`

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

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

##### `fully_gt`

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

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

##### `not_lt`

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

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

##### `not_gt`

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

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

##### `adjacent_to`

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

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

#### 使用边界进行查询

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

##### `startswith`

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

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

##### `endswith`

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

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

##### `isempty`

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

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

##### `lower_inc`

New in Django 3.1.

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

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

##### `lower_inf`

New in Django 3.1.

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

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

##### `upper_inc`

New in Django 3.1.

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

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

##### `upper_inf`

New in Django 3.1.

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

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

### 定义自己的范围类型

PostgreSQL 允许自定义范围类型的定义。Django 的模型和表单字段实现使用下面的基类，psycopg2 提供了一个 `register_range()` 来允许使用自定义范围类型。

class `RangeField`(**options)

  模型范围字段的基类。

  `base_field`

    要使用的模型字段类。

  `range_type`

    要使用的 psycopg2 范围类型。

  `form_field`

    要使用的表单字段类。应该是 `django.contrib.postgres.forms.BaseRangeField` 的子类。

class `django.contrib.postgres.forms.``BaseRangeField`

  表范围字段的基类。

  `base_field`

    要使用的表字段。

  `range_type`

    要使用的 psycopg2 范围类型。

### 范围操作

class `RangeOperators`

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

    class RangeOperators:
        EQUAL = '='
        NOT_EQUAL = '<>'
        CONTAINS = '@>'
        CONTAINED_BY = '<@'
        OVERLAPS = '&&'
        FULLY_LT = '<<'
        FULLY_GT = '>>'
        NOT_LT = '&>'
        NOT_GT = '&<'
        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 `_ 。