Spec-Zone.ru › Django 5.1

Поля модели, специфичные для 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).

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

  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 и как 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/

Spec-Zone.ru

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