Поля моделей, специфичные для PostgreSQL
Все эти поля доступны из модуля django.contrib.postgres.fields.
Индексирование этих полей
Index и Field.db_index оба создают индекс B-дерева, что не особенно полезно при запросе к сложным типам данных. Индексы, такие как 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).Возможна вложенность полей массивов — вы можете указать экземпляр
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],
])
Если требуются неровные формы, то базовое поле должно быть сделано nullable, а значения заполнены 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 использует индексацию с 1 для полей массивов при записи SQL запросов. Однако эти индексы и те, что используются в 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 использует индексацию с 1 для полей массивов при записи SQL запросов. Однако эти срезы и те, что используются в indexes, используют индексацию с 0 для согласованности с Python.
Многомерные массивы с индексами и срезами
PostgreSQL имеет довольно специфическое поведение при использовании индексов и срезов в многомерных массивах. Всегда работает использование индексов для доступа к конечным данным, но большинство других срезов ведут себя странно на уровне базы данных и не могут быть логично и последовательно поддерживаемы Django.
CIText поля
-
class CIText(**options) -
Миксин для создания регистронезависимых текстовых полей, основанных на типе citext. Прочитайте о соображениях производительности перед использованием.
Для использования
citext, используйте операциюCITextExtension, чтобы настроить расширение citext в PostgreSQL перед первойCreateModelмиграцией.Если вы используете
ArrayFieldполейCIText, вы должны добавить'django.contrib.postgres'в своиINSTALLED_APPS, в противном случае значения полей будут отображаться как строки, например,'{thoughts,django}'.Представлены несколько полей, использующих этот миксин:
-
class CICharField(**options)
-
class CIEmailField(**options)
-
class CITextField(**options) -
Эти поля являются подклассами
CharField,EmailFieldиTextFieldсоответственно.max_lengthв базе данных не будут проверяться, так какcitextведет себя аналогично типуtextв PostgreSQL.
Регистронезависимые сортировки
В PostgreSQL 12+ предпочтительнее использовать недетерминированные сортировки вместо расширения citext. Их можно создать с помощью миграции CreateCollation. Подробнее см. Управление сортировками с помощью миграций и документацию PostgreSQL о недетерминированных сортировках.
HStoreField
-
class HStoreField(**options) -
Поле для хранения пар «ключ-значение». Используемый Python-тип —
dict. Ключи должны быть строками, а значения могут быть строками или нулевыми значениями (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>]>
Если ключ, по которому вы хотите произвести поиск, совпадает с именем другого поиска, необходимо использовать поиск 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. Эти поля используются для хранения диапазона значений; например, начальной и конечной временных меток события или диапазона возрастов, для которых подходит активность.
Все поля диапазонов преобразуются в объекты диапазонов psycopg2 в Python, но также принимают кортежи в качестве входных данных, если информация о границах не нужна. По умолчанию используется включенная нижняя граница, исключенная верхняя граница, то есть [) (подробнее см. документацию 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и какDateTimeTZRangeв Python.
DateRangeField
-
class DateRangeField(**options) -
Хранит диапазон дат. Основан на
DateField. Представлен в базе данных какdaterangeи какDateRangeв Python.Независимо от границ, указанных при сохранении данных, 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>]>
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 используют базовые классы ниже, а 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, которые могут использоваться вместе с типами данных диапазона (см. документацию 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/4.0/ref/contrib/postgres/fields/