Spec-Zone.ru › Django 5.2

Поля моделей, специфичные для 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. Ключи должны быть строками, а значения могут быть либо строками, либо нулевыми (None в Python).

Для использования этого поля необходимо:

  1. Добавить 'django.contrib.postgres' в свой INSTALLED_APPS.
  2. Настроить расширение 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, а в 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/5.2/ref/contrib/postgres/fields/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API