Поля модели, специфичные для 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) и файлы (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],
]
)
Если требуются нерегулярные формы, то базовая поле должно быть сделано 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", "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 []>
Примечание
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.
Вы увидите ошибку типа
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. Эти поля используются для хранения диапазона значений; например, начальной и конечной даты и времени события или диапазона возрастов, для которых подходит определенная активность.
Все поля диапазонов преобразуются в объекты psycopg Range в Python, но также принимают кортежи в качестве входных данных, если нет необходимости в информации о границах. По умолчанию включена нижняя граница, исключена верхняя, то есть [) (см. документацию PostgreSQL для получения подробной информации о различных границах). Значения по умолчанию для границ можно изменить для полей диапазонов, не являющихся дискретными (DateTimeRangeField и 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 всегда возвращает диапазон в канонической форме, включающей нижнюю границу и исключающую верхнюю, то есть
[).
DecimalRangeField
-
class DecimalRangeField(default_bounds='[)', **options) -
Хранит диапазон чисел с плавающей запятой. Основано на
DecimalField. Представлено в базе данных какnumrangeи какdjango.db.backends.postgresql.psycopg_any.NumericRangeв Python.-
default_bounds -
Необязательно. Значение
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 -
Необязательно. Значение
boundsдля входных списков и кортежей. По умолчанию включена нижняя граница, исключена верхняя, то есть[)(см. документацию PostgreSQL для получения подробной информации о различных границах).default_boundsне используется для входных данныхdjango.db.backends.postgresql.psycopg_any.DateTimeTZRange.
-
DateRangeField
-
class DateRangeField(**options) -
Хранит диапазон дат. Основано на
DateField. Представлено в базе данных какdaterangeи как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 также доступен для типов полей без диапазона: 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/5.1/ref/contrib/postgres/fields/