Специальные поля моделей PostgreSQL
Все эти поля доступны из модуля django.contrib.postgres.fields.
Индексация этих полей
Index и Field.db_index создают B-tree-индекс, который не особенно полезен при запросах к сложным типам данных. Лучше подходят такие индексы, как GinIndex и GistIndex, однако выбор индекса зависит от используемых запросов. Как правило, GiST может быть хорошим выбором для полей диапазонов и 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) и файловыми полями (FileFieldиImageField).Можно вкладывать поля массивов друг в друга — для этого укажите экземпляр
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", "tutorial"])
>>> 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>]>
>>> Post.objects.filter(tags__overlap=Post.objects.values_list("tags"))
<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 []>
Примечание
При записи обычного SQL для полей-массивов PostgreSQL использует индексацию с 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>]>
Примечание
При записи обычного SQL для полей-массивов PostgreSQL использует индексацию с 1. Однако в этих срезах и в indexes используется индексация с 0, чтобы она соответствовала Python.
Многомерные массивы с индексами и срезами
При использовании индексов и срезов для многомерных массивов PostgreSQL ведет себя довольно необычно. Индексы всегда позволяют добраться до конечных базовых данных, однако большинство других срезов на уровне базы данных работают странно, и Django не может поддерживать их логично и единообразно.
HStoreField
-
class HStoreField(**options) -
Поле для хранения пар «ключ — значение». Используемый тип данных Python —
dict. Ключи должны быть строками, а значения могут быть строками или null (Noneв Python).Чтобы использовать это поле, необходимо:
- Добавить
'django.contrib.postgres'вINSTALLED_APPS. - Настроить расширение hstore в PostgreSQL.
Если пропустить первый шаг, вы увидите ошибку вроде
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>]>
или использовать выражения F() для добавления значения ключа в аннотацию. Например:
>>> from django.db.models import F
>>> rufus = Dog.objects.annotate(breed=F("data__breed"))[0]
>>> rufus.breed
'labrador'
Если ключ, по которому нужно выполнить запрос, совпадает с именем другого поискового выражения, вместо него необходимо использовать поисковое выражение hstorefield.contains.
Примечание
Преобразования ключей также можно комбинировать со следующими поисковыми выражениями: contains, icontains, endswith, iendswith, iexact, regex, iregex, startswith и istartswith.
Предупреждение
Поскольку ключом в значении 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>]>
Поля диапазонов
Существует пять типов полей диапазонов, соответствующих встроенным типам диапазонов PostgreSQL. Эти поля используются для хранения диапазона значений, например времени начала и окончания события или диапазона возрастов, для которых подходит какое-либо занятие.
Все поля диапазонов преобразуются в Python в объекты Range psycopg, но также принимают кортежи в качестве входных данных, если сведения о границах не нужны. По умолчанию нижняя граница включена, а верхняя исключена, то есть [) (подробности см. в документации PostgreSQL о различных границах). Границы по умолчанию можно изменить для недискретных полей диапазонов (DateTimeRangeField и DecimalRangeField) с помощью аргумента default_bounds.
PostgreSQL приводит диапазон без точек к пустому диапазону
Диапазон с одинаковыми значениями включённой нижней и исключённой верхней границ, например Range(datetime.date(2005, 6, 21),
datetime.date(2005, 6, 21)) или [4, 4), не содержит точек. При сохранении в базе данных PostgreSQL преобразует такое значение в пустой диапазон, и исходные значения границ будут потеряны. Подробности см. в документации PostgreSQL.
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 -
Необязательный атрибут. Значение
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 -
Необязательный атрибут. Значение
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 всегда возвращает диапазон в канонической форме, включающей нижнюю границу и исключающей верхнюю, то есть
[).
Запросы к полям диапазонов
Для полей диапазонов доступны различные пользовательские операции поиска и преобразования. Они доступны для всех перечисленных выше полей. В примерах ниже используется следующая модель:
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 django.db.backends.postgresql.psycopg_any 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 django.db.backends.postgresql.psycopg_any 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>]>
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
Возвращает объекты с включёнными или исключёнными нижними границами в зависимости от переданного логического значения. Можно объединять с допустимыми операциями поиска для BooleanField.
>>> Event.objects.filter(ages__lower_inc=True) <QuerySet [<Event: Soft play>, <Event: Pub trip>]>
lower_inf
Возвращает объекты с неограниченной (бесконечной) или ограниченной нижней границей в зависимости от переданного логического значения. Можно объединять с допустимыми операциями поиска для BooleanField.
>>> Event.objects.filter(ages__lower_inf=True) <QuerySet []>
upper_inc
Возвращает объекты с включёнными или исключёнными верхними границами в зависимости от переданного логического значения. Можно объединять с допустимыми операциями поиска для BooleanField.
>>> Event.objects.filter(ages__upper_inc=True) <QuerySet []>
upper_inf
Возвращает объекты с неограниченной (бесконечной) или ограниченной верхней границей в зависимости от переданного логического значения. Можно объединять с допустимыми операциями поиска для BooleanField.
>>> Event.objects.filter(ages__upper_inf=True) <QuerySet [<Event: Pub trip>]>
Определение собственных типов диапазонов
PostgreSQL позволяет определять пользовательские типы диапазонов. Реализации полей моделей и форм Django используют приведённые ниже базовые классы, а psycopg предоставляет register_range(), позволяющий использовать пользовательские типы диапазонов.
-
class RangeField(**options) -
Базовый класс полей диапазонов модели.
-
base_field -
Класс поля модели, который следует использовать.
-
range_type -
Тип диапазона, который следует использовать.
-
form_field -
Класс поля формы, который следует использовать. Должен быть подклассом
django.contrib.postgres.forms.BaseRangeField.
-
-
class django.contrib.postgres.forms.BaseRangeField -
Базовый класс полей диапазонов формы.
-
base_field -
Поле формы, которое следует использовать.
-
range_type -
Тип диапазона, который следует использовать.
-
Операторы диапазонов
-
class RangeOperators
PostgreSQL предоставляет набор операторов SQL, которые можно использовать с типами данных диапазонов (полное описание операторов диапазонов см. в документации PostgreSQL). Этот класс предназначен для удобства и помогает избежать опечаток. Имена операторов совпадают с именами соответствующих операций поиска.
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. Полное описание см. в документации PostgreSQL.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/ref/contrib/postgres/fields/