Поля конкретной модели PostgreSQL¶
Все эти поля доступны из модуля django.contrib.postgres.fields.
Индексирование этих полей¶
Index и Field.db_index оба создают индекс B-дерева, что не особенно полезно при запросе сложных типов данных. Такие индексы, как GinIndex и GistIndex, подходят лучше, хотя выбор индекса зависит от используемых вами запросов. Как правило, GiST может быть хорошим выбором для полей range и HStoreField, а GIN может быть полезен для 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],
]
)
Если требуются нестандартные формы, то базовое поле должно быть обнуляемым, а значения дополняться «Нет».
Запрос 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>]>
перекрытие¶
Возвращает объекты, в которых данные разделяют любые результаты с переданными значениями. Использует оператор 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>]>
лен¶
Возвращает длину массива. После этого доступны поиски для 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 логически и последовательно.
HStoreField¶
- class HStoreField(**options)¶
Поле для хранения пар ключ-значение. Используемый тип данных Python — «dict». Ключи должны быть строками, а значения могут быть либо строками, либо значениями NULL («None» в Python).
Чтобы использовать это поле, вам необходимо:
Добавьте
'django.contrib.postgres'в настройки:INSTALLED_APPS.Настройте расширение hstore в PostgreSQL.
Вы увидите ошибку типа «невозможно адаптировать тип «dict», если пропустите первый шаг, или «тип «hstore» не существует», если пропустите второй.
Примечание
В некоторых случаях может быть полезно потребовать или ограничить ключи, действительные для данного поля. Это можно сделать с помощью 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. Возвращаемые объекты — это те объекты, в поле которых содержатся все заданные пары ключ-значение. Он использует оператор 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>]>
ключи¶
Возвращает объекты, где массив ключей имеет заданное значение. Обратите внимание, что надежность порядка не гарантируется, поэтому это преобразование в основном полезно использовать в сочетании с поиском по ArrayField. Использует функцию SQL keys(). Например:
>>> 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>]>
ценности¶
Возвращает объекты, в которых массив значений является заданным значением. Обратите внимание, что надежность порядка не гарантируется, поэтому это преобразование в основном полезно использовать в сочетании с поиском по 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. Эти поля используются для хранения диапазона значений; например, временные метки начала и окончания события или диапазон возрастов, для которого подходит занятие.
Все поля диапазона преобразуются в psycopg Range объекты в Python, но также принимают кортежи в качестве входных данных, если информация о границах не требуется. По умолчанию нижняя граница включена, а верхняя граница исключена, то есть [) (подробную информацию о различных границах`_ см. в документации PostgreSQL). Границы по умолчанию можно изменить для полей недискретного диапазона (:class:`.DateTimeRangeField` и :class:`.DecimalRangeField`) с помощью аргумента ``default_bounds.
IntegerRangeField¶
- class IntegerRangeField(**options)¶
Хранит диапазон целых чисел. На основе
IntegerField. Представлено int4range в базе данных и django.db.backends.postgresql.psycopg_any.NumericRange в Python.Независимо от границ, указанных при сохранении данных, PostgreSQL всегда возвращает диапазон в канонической форме, который включает нижнюю границу и исключает верхнюю границу, то есть
[).
BigIntegerRangeField¶
- class BigIntegerRangeField(**options)¶
Хранит диапазон больших целых чисел. На основе
BigIntegerField. Представлено int8range в базе данных и django.db.backends.postgresql.psycopg_any.NumericRange в Python.Независимо от границ, указанных при сохранении данных, PostgreSQL всегда возвращает диапазон в канонической форме, который включает нижнюю границу и исключает верхнюю границу, то есть
[).
Десятичноеполедиапазона¶
- class DecimalRangeField(default_bounds='[)', **options)¶
Хранит диапазон значений с плавающей запятой. На основе
DecimalField. Представлено диапазоном чисел в базе данных и django.db.backends.postgresql.psycopg_any.NumericRange в Python.- default_bounds¶
Необязательный. Значение границ для входных данных списков и кортежей. По умолчанию нижняя граница включена, а верхняя граница исключена, то есть
[)(подробную информацию оразличных границах`_ см. в документации PostgreSQL). ``default_boundsне используется для входных данныхdjango.db.backends.postgresql.psycopg_any.NumericRange.
DateTimeRangeField¶
- class DateTimeRangeField(default_bounds='[)', **options)¶
Хранит диапазон временных меток. На основе
DateTimeField. Представлено tstzrange в базе данных и django.db.backends.postgresql.psycopg_any.DateTimeTZRange в Python.- default_bounds¶
Необязательный. Значение границ для входных данных списков и кортежей. По умолчанию нижняя граница включена, а верхняя граница исключена, то есть
[)(подробную информацию оразличных границах`_ см. в документации PostgreSQL). ``default_boundsне используется для входных данныхdjango.db.backends.postgresql.psycopg_any.DateTimeTZRange.
ДатаРангеФилд¶
- class DateRangeField(**options)¶
Хранит диапазон дат. На основе
DateField. Представлено диапазоном дат в базе данных и django.db.backends.postgresql.psycopg_any.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 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 также доступен для типов полей, не входящих в диапазон: 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>]>
перекрытие¶
>>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
<QuerySet [<Event: Soft play>]>
Функции сравнения¶
Поля диапазона поддерживают стандартные поиски: lt, gt, lte и gte. Это не особенно полезно — сначала сравниваются нижние границы, а затем только при необходимости верхние границы. Эта стратегия также используется для заказа по полю диапазона. Лучше использовать конкретные операторы сравнения диапазонов.
полностью_lt¶
Возвращаемые диапазоны строго меньше переданного диапазона. Другими словами, все точки в возвращаемом диапазоне меньше всех точек в переданном диапазоне.
>>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15))
<QuerySet [<Event: Soft play>]>
полностью_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>]>
пустой¶
Возвращаемые объекты представляют собой пустые диапазоны. Может быть привязан к допустимому поиску для 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 RangeOperators¶
PostgreSQL предоставляет набор операторов SQL, которые можно использовать вместе с типами данных диапазона (полную информацию об операторах диапазона см. в документации PostgreSQL <https://www.postgresql.org/docs/current/functions-range.html#RANGE-OPERATORS-TABLE>`_). Этот класс задуман как удобный способ избежать опечаток. Имена операторов перекрываются с именами соответствующих поисков.
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 <https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-INCLUSIVITY>`_.