Spec-Zone.ru › Django 4.0

Поля моделей, специфичные для PostgreSQL

Все эти поля доступны из модуля django.contrib.postgres.fields.

Индексирование этих полей

Index и Field.db_index оба создают индекс B-дерева, что не особенно полезно при запросе к сложным типам данных. Индексы, такие как GinIndex и GistIndex, более подходят, хотя выбор индекса зависит от используемых запросов. В целом, GiST может быть хорошим выбором для полей диапазона и HStoreField, а GIN может быть полезен для ArrayField.

ArrayField

class ArrayField(base_field, size=None, **options)

Поле для хранения списков данных. Большинство типов полей могут быть использованы, и вы передаёте другой экземпляр поля в качестве base_field. Вы также можете указать size. ArrayField могут быть вложены для хранения многомерных массивов.

Если вы задаёте полю default, убедитесь, что это вызываемый объект, такой как list (для пустого значения по умолчанию) или вызываемый объект, возвращающий список (такой как функция). Неправильное использование default=[] создаёт изменяемое значение по умолчанию, которое используется всеми экземплярами ArrayField.

base_field

Это обязательный аргумент.

Указывает базовый тип данных и поведение для массива. Это должен быть экземпляр подкласса Field. Например, это может быть IntegerField или CharField. Разрешается большинство типов полей, за исключением полей, обрабатывающих реляционные данные (ForeignKey, OneToOneField и ManyToManyField).

Возможна вложенность полей массивов — вы можете указать экземпляр ArrayField в качестве base_field. Например:

from django.contrib.postgres.fields import ArrayField
from django.db import models

class ChessBoard(models.Model):
    board = ArrayField(
        ArrayField(
            models.CharField(max_length=10, blank=True),
            size=8,
        ),
        size=8,
    )

Преобразование значений между базой данных и моделью, проверка данных и конфигурация, а также сериализация делегируются базовому полю.

size

Это необязательный аргумент.

Если он передан, массив будет иметь максимальный размер, как указано. Это будет передано в базу данных, хотя в настоящее время PostgreSQL не накладывает ограничение.

Примечание

При вложенности ArrayField, независимо от того, используете ли вы параметр size, PostgreSQL требует, чтобы массивы были прямоугольными:

from django.contrib.postgres.fields import ArrayField
from django.db import models

class Board(models.Model):
    pieces = ArrayField(ArrayField(models.IntegerField()))

# Valid
Board(pieces=[
    [2, 3],
    [2, 1],
])

# Not valid
Board(pieces=[
    [2, 3],
    [2],
])

Если требуются неровные формы, то базовое поле должно быть сделано nullable, а значения заполнены None.

Запросы к ArrayField

Существует ряд пользовательских поисков и преобразований для ArrayField. Мы будем использовать следующую примерную модель:

from django.contrib.postgres.fields import ArrayField
from django.db import models

class Post(models.Model):
    name = models.CharField(max_length=200)
    tags = ArrayField(models.CharField(max_length=200), blank=True)

    def __str__(self):
        return self.name

contains

Поиск contains переопределяется для ArrayField. Возвращаемые объекты — те, где переданные значения являются подмножеством данных. Используется оператор SQL @>. Например:

>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])

>>> Post.objects.filter(tags__contains=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__contains=['django'])
<QuerySet [<Post: First post>, <Post: Third post>]>

>>> Post.objects.filter(tags__contains=['django', 'thoughts'])
<QuerySet [<Post: First post>]>

contained_by

Это обратное к поиску contains — возвращаемые объекты — те, где данные являются подмножеством переданных значений. Используется оператор SQL <@. Например:

>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])

>>> Post.objects.filter(tags__contained_by=['thoughts', 'django'])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial'])
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>

overlap

Возвращает объекты, где данные имеют какие-либо значения, совпадающие с переданными. Используется оператор SQL &&. Например:

>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])

>>> Post.objects.filter(tags__overlap=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>

len

Возвращает длину массива. Доступные после этого поиски — те, что доступны для IntegerField. Например:

>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])

>>> Post.objects.filter(tags__len=1)
<QuerySet [<Post: Second post>]>

Преобразования индексов

Преобразования индексов индексируют в массив. Можно использовать любое неотрицательное целое число. Ошибки не возникают, если оно превышает size массива. Доступные после преобразования поиски — те, что доступны для base_field. Например:

>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])

>>> Post.objects.filter(tags__0='thoughts')
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__1__iexact='Django')
<QuerySet [<Post: First post>]>

>>> Post.objects.filter(tags__276='javascript')
<QuerySet []>

Примечание

PostgreSQL использует индексацию с 1 для полей массивов при записи SQL запросов. Однако эти индексы и те, что используются в slices, используют индексацию с 0 для согласованности с Python.

Преобразования срезов

Преобразования срезов берут срез массива. Можно использовать любые два неотрицательных целых числа, разделенных одним символом подчеркивания. Доступные после преобразования поиски не меняются. Например:

>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['django', 'python', 'thoughts'])

>>> Post.objects.filter(tags__0_1=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__0_2__contains=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>

Примечание

PostgreSQL использует индексацию с 1 для полей массивов при записи SQL запросов. Однако эти срезы и те, что используются в indexes, используют индексацию с 0 для согласованности с Python.

Многомерные массивы с индексами и срезами

PostgreSQL имеет довольно специфическое поведение при использовании индексов и срезов в многомерных массивах. Всегда работает использование индексов для доступа к конечным данным, но большинство других срезов ведут себя странно на уровне базы данных и не могут быть логично и последовательно поддерживаемы Django.

CIText поля

class CIText(**options)

Миксин для создания регистронезависимых текстовых полей, основанных на типе citext. Прочитайте о соображениях производительности перед использованием.

Для использования citext, используйте операцию CITextExtension, чтобы настроить расширение citext в PostgreSQL перед первой CreateModel миграцией.

Если вы используете ArrayField полей CIText, вы должны добавить 'django.contrib.postgres' в свои INSTALLED_APPS, в противном случае значения полей будут отображаться как строки, например, '{thoughts,django}'.

Представлены несколько полей, использующих этот миксин:

class CICharField(**options)
class CIEmailField(**options)
class CITextField(**options)

Эти поля являются подклассами CharField, EmailField и TextField соответственно.

max_length в базе данных не будут проверяться, так как citext ведет себя аналогично типу text в PostgreSQL.

Регистронезависимые сортировки

В PostgreSQL 12+ предпочтительнее использовать недетерминированные сортировки вместо расширения citext. Их можно создать с помощью миграции CreateCollation. Подробнее см. Управление сортировками с помощью миграций и документацию PostgreSQL о недетерминированных сортировках.

HStoreField

class HStoreField(**options)

Поле для хранения пар «ключ-значение». Используемый Python-тип — dict. Ключи должны быть строками, а значения могут быть строками или нулевыми значениями (None в Python).

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

  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>]>

Если ключ, по которому вы хотите произвести поиск, совпадает с именем другого поиска, необходимо использовать поиск hstorefield.contains вместо него.

Примечание

Преобразования ключей также могут быть объединены с: contains, icontains, endswith, iendswith, iexact, regex, iregex, startswith и istartswith запросами.

Предупреждение

Поскольку любой строковый ключ может быть ключом значения hstore, любой поиск, кроме перечисленных ниже, будет интерпретирован как поиск по ключу. Ошибки не генерируются. Будьте внимательны к ошибкам ввода и всегда проверяйте, что ваши запросы работают так, как вы ожидаете.

contains

Поиск contains переопределен для HStoreField. Возвращаемые объекты — те, где все заданные dict пар «ключ-значение» содержатся в поле. Используется оператор SQL @>. Например:

>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
>>> Dog.objects.create(name='Fred', data={})

>>> Dog.objects.filter(data__contains={'owner': 'Bob'})
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>

>>> Dog.objects.filter(data__contains={'breed': 'collie'})
<QuerySet [<Dog: Meg>]>

contained_by

Это обратное значение для поиска contains — возвращаемые объекты будут теми, где пары «ключ-значение» объекта являются подмножеством переданного значения. Используется оператор SQL <@. Например:

>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
>>> Dog.objects.create(name='Fred', data={})

>>> Dog.objects.filter(data__contained_by={'breed': 'collie', 'owner': 'Bob'})
<QuerySet [<Dog: Meg>, <Dog: Fred>]>

>>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
<QuerySet [<Dog: Fred>]>

has_key

Возвращает объекты, где указанный ключ есть в данных. Используется оператор SQL ?. Например:

>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})

>>> Dog.objects.filter(data__has_key='owner')
<QuerySet [<Dog: Meg>]>

has_any_keys

Возвращает объекты, где любой из указанных ключей есть в данных. Используется оператор SQL ?|. Например:

>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'owner': 'Bob'})
>>> Dog.objects.create(name='Fred', data={})

>>> Dog.objects.filter(data__has_any_keys=['owner', 'breed'])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>

has_keys

Возвращает объекты, где все указанные ключи есть в данных. Используется оператор SQL ?&. Например:

>>> Dog.objects.create(name='Rufus', data={})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})

>>> Dog.objects.filter(data__has_keys=['breed', 'owner'])
<QuerySet [<Dog: Meg>]>

keys

Возвращает объекты, где массив ключей — это заданное значение. Обратите внимание, что порядок не гарантирован, поэтому это преобразование в основном используется в сочетании с запросами к ArrayField. Используется SQL-функция akeys(). Например:

>>> Dog.objects.create(name='Rufus', data={'toy': 'bone'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})

>>> Dog.objects.filter(data__keys__overlap=['breed', 'toy'])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>

values

Возвращает объекты, где массив значений — это заданное значение. Обратите внимание, что порядок не гарантирован, поэтому это преобразование в основном используется в сочетании с запросами к ArrayField. Используется SQL-функция avals(). Например:

>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})

>>> Dog.objects.filter(data__values__contains=['collie'])
<QuerySet [<Dog: Meg>]>

Поля диапазонов

Существует пять типов полей диапазонов, соответствующих встроенным типам диапазонов в PostgreSQL. Эти поля используются для хранения диапазона значений; например, начальной и конечной временных меток события или диапазона возрастов, для которых подходит активность.

Все поля диапазонов преобразуются в объекты диапазонов psycopg2 в Python, но также принимают кортежи в качестве входных данных, если информация о границах не нужна. По умолчанию используется включенная нижняя граница, исключенная верхняя граница, то есть [) (подробнее см. документацию PostgreSQL о различных границах).

IntegerRangeField

class IntegerRangeField(**options)

Хранит диапазон целых чисел. Основан на IntegerField. Представлен в базе данных как int4range и в Python как NumericRange.

Независимо от указанных границ при сохранении данных PostgreSQL всегда возвращает диапазон в канонической форме, которая включает нижнюю границу и исключает верхнюю, то есть [).

BigIntegerRangeField

class BigIntegerRangeField(**options)

Хранит диапазон больших целых чисел. Основан на BigIntegerField. Представлен в базе данных как int8range и в Python как NumericRange.

Независимо от указанных границ при сохранении данных PostgreSQL всегда возвращает диапазон в канонической форме, которая включает нижнюю границу и исключает верхнюю, то есть [).

DecimalRangeField

class DecimalRangeField(**options)

Хранит диапазон чисел с плавающей точкой. Основан на DecimalField. Представлен в базе данных как numrange и в Python как NumericRange.

DateTimeRangeField

class DateTimeRangeField(**options)

Хранит диапазон временных меток. Основан на DateTimeField. Представлен в базе данных как tstzrange и как DateTimeTZRange в Python.

DateRangeField

class DateRangeField(**options)

Хранит диапазон дат. Основан на DateField. Представлен в базе данных как daterange и как DateRange в Python.

Независимо от границ, указанных при сохранении данных, PostgreSQL всегда возвращает диапазон в канонической форме, которая включает нижнюю границу и исключает верхнюю границу, то есть [).

Запрос к полям диапазона

Существует ряд пользовательских поисковых запросов и преобразований для полей диапазона. Они доступны для всех вышеперечисленных полей, но мы будем использовать следующую примерную модель:

from django.contrib.postgres.fields import IntegerRangeField
from django.db import models

class Event(models.Model):
    name = models.CharField(max_length=200)
    ages = IntegerRangeField()
    start = models.DateTimeField()

    def __str__(self):
        return self.name

Мы также будем использовать следующие примерные объекты:

>>> import datetime
>>> from django.utils import timezone
>>> now = timezone.now()
>>> Event.objects.create(name='Soft play', ages=(0, 10), start=now)
>>> Event.objects.create(name='Pub trip', ages=(21, None), start=now - datetime.timedelta(days=1))

и NumericRange:

>>> from psycopg2.extras import NumericRange

Функции включения

Как и в других полях PostgreSQL, существуют три стандартных оператора включения: contains, contained_by и overlap, использующих операторы SQL @>, <@, и && соответственно.

contains
>>> Event.objects.filter(ages__contains=NumericRange(4, 5))
<QuerySet [<Event: Soft play>]>
contained_by
>>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
<QuerySet [<Event: Soft play>]>

Поиск contained_by также доступен для типов полей без диапазона: SmallAutoField, AutoField, BigAutoField, SmallIntegerField, IntegerField, BigIntegerField, DecimalField, FloatField, DateField, и DateTimeField. Например:

>>> from psycopg2.extras import DateTimeTZRange
>>> Event.objects.filter(
...     start__contained_by=DateTimeTZRange(
...         timezone.now() - datetime.timedelta(hours=1),
...         timezone.now() + datetime.timedelta(hours=1),
...     ),
... )
<QuerySet [<Event: Soft play>]>
overlap
>>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
<QuerySet [<Event: Soft play>]>

Функции сравнения

Поля диапазона поддерживают стандартные поиски: lt, gt, lte и gte. Они не особенно полезны — они сначала сравнивают нижние границы, а затем верхние границы только при необходимости. Это также стратегия, используемая для сортировки по полю диапазона. Лучше использовать специфические операторы сравнения диапазонов.

fully_lt

Возвращаемые диапазоны строго меньше переданного диапазона. Другими словами, все точки в возвращаемом диапазоне меньше всех точек в переданном диапазоне.

>>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15))
<QuerySet [<Event: Soft play>]>
fully_gt

Возвращаемые диапазоны строго больше переданного диапазона. Другими словами, все точки в возвращаемом диапазоне больше всех точек в переданном диапазоне.

>>> Event.objects.filter(ages__fully_gt=NumericRange(11, 15))
<QuerySet [<Event: Pub trip>]>
not_lt

Возвращаемые диапазоны не содержат точек, меньших переданного диапазона, то есть нижняя граница возвращаемого диапазона не меньше нижней границы переданного диапазона.

>>> Event.objects.filter(ages__not_lt=NumericRange(0, 15))
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>
not_gt

Возвращаемые диапазоны не содержат точек, больших переданного диапазона, то есть верхняя граница возвращаемого диапазона не больше верхней границы переданного диапазона.

>>> Event.objects.filter(ages__not_gt=NumericRange(3, 10))
<QuerySet [<Event: Soft play>]>
adjacent_to

Возвращаемые диапазоны имеют общую границу с переданным диапазоном.

>>> Event.objects.filter(ages__adjacent_to=NumericRange(10, 21))
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>

Запрос с использованием границ

Поля диапазона поддерживают несколько дополнительных поисков.

startswith

Возвращаемые объекты имеют заданную нижнюю границу. Может быть объединен с допустимыми поисками для базового поля.

>>> Event.objects.filter(ages__startswith=21)
<QuerySet [<Event: Pub trip>]>
endswith

Возвращаемые объекты имеют заданную верхнюю границу. Может быть объединен с допустимыми поисками для базового поля.

>>> Event.objects.filter(ages__endswith=10)
<QuerySet [<Event: Soft play>]>
isempty

Возвращаемые объекты — пустые диапазоны. Может быть объединен с допустимыми поисками для BooleanField.

>>> Event.objects.filter(ages__isempty=True)
<QuerySet []>
lower_inc

Возвращает объекты с включительными или исключительными нижними границами в зависимости от переданного булевого значения. Может быть объединен с допустимыми поисками для BooleanField.

>>> Event.objects.filter(ages__lower_inc=True)
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>
lower_inf

Возвращает объекты, у которых нижняя граница неограничена (бесконечна) или ограничена, в зависимости от переданного булевого значения. Может быть объединен с допустимыми поисками для BooleanField.

>>> Event.objects.filter(ages__lower_inf=True)
<QuerySet []>
upper_inc

Возвращает объекты с включительными или исключительными верхними границами в зависимости от переданного булевого значения. Может быть объединен с допустимыми поисками для BooleanField.

>>> Event.objects.filter(ages__upper_inc=True)
<QuerySet []>
upper_inf

Возвращает объекты, у которых верхняя граница неограничена (бесконечна) или ограничена, в зависимости от переданного булевого значения. Может быть объединен с допустимыми поисками для BooleanField.

>>> Event.objects.filter(ages__upper_inf=True)
<QuerySet [<Event: Pub trip>]>

Определение собственных типов диапазонов

PostgreSQL позволяет определять пользовательские типы диапазонов. Реализации полей модели и формы Django используют базовые классы ниже, а psycopg2 предоставляет register_range() для использования пользовательских типов диапазонов.

class RangeField(**options)

Базовый класс для полей диапазона модели.

base_field

Класс поля модели для использования.

range_type

Тип диапазона psycopg2 для использования.

form_field

Класс поля формы для использования. Должен быть подклассом django.contrib.postgres.forms.BaseRangeField.

class django.contrib.postgres.forms.BaseRangeField

Базовый класс для полей формы диапазона.

base_field

Используемое поле формы.

range_type

Тип диапазона psycopg2 для использования.

Операторы диапазона

class RangeOperators

PostgreSQL предоставляет набор операторов SQL, которые могут использоваться вместе с типами данных диапазона (см. документацию PostgreSQL для получения подробной информации об операторах диапазона). Этот класс предназначен как удобный способ избежать опечаток. Названия операторов совпадают с именами соответствующих поисков.

class RangeOperators:
    EQUAL = '='
    NOT_EQUAL = '<>'
    CONTAINS = '@>'
    CONTAINED_BY = '<@'
    OVERLAPS = '&&'
    FULLY_LT = '<<'
    FULLY_GT = '>>'
    NOT_LT = '&>'
    NOT_GT = '&<'
    ADJACENT_TO = '-|-'

Выражения RangeBoundary()

class RangeBoundary(inclusive_lower=True, inclusive_upper=False)
inclusive_lower

Если True (по умолчанию), нижняя граница включена '[', в противном случае она исключена '('.

inclusive_upper

Если False (по умолчанию), верхняя граница исключена ')', в противном случае она включена ']'.

Выражение RangeBoundary() представляет границы диапазона. Его можно использовать с пользовательскими функциями диапазонов, которые ожидают границы, например, для определения ExclusionConstraint. См. документацию PostgreSQL для получения полной информации.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.0/ref/contrib/postgres/fields/

Spec-Zone.ru

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