Spec-Zone.ru › Django 1.10

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

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

ArrayField

class ArrayField(base_field, size=None, **options) [source]

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

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

base_field

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

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

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

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

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

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

Запросы к ArrayField

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

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

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

    def __str__(self):  # __unicode__ on Python 2
        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.

Индексирование ArrayField

В настоящее время использование db_index создаст индекс btree. Это не особенно помогает при запросах. Более полезный индекс – индекс GIN, который вы должны создать с помощью операции RunSQL.

HStoreField

class HStoreField(**options) [source]

Поле для хранения сопоставлений строк со строками. Используемый тип данных Python – dict.

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

  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):  # __unicode__ on Python 2
        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 вместо него.

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

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

contains

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

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

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

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

contained_by

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

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

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

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

has_key

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

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

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

has_any_keys

Новая функция в Django 1.9.

Возвращает объекты, где любой из указанных ключей присутствует в данных. Используется 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 функция avalues(). Например:

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

JSONField

Новая функция в Django 1.9.
class JSONField(**options) [source]

Поле для хранения данных, закодированных в формате JSON. В Python данные представлены в их собственном формате: словари, списки, строки, числа, булевы значения и None.

Если вам нужно хранить другие типы данных, вам нужно их сначала сериализовать. Например, вы можете преобразовать datetime в строку. Возможно, также захотите преобразовать строку обратно в datetime при получении данных из базы данных. Существуют сторонние JSONField реализации, которые автоматически выполняют подобные операции.

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

Примечание

PostgreSQL имеет два встроенных типа данных, основанных на JSON: json и jsonb. Основное различие между ними заключается в том, как они хранятся и как по ним можно выполнять запросы. Поле json в PostgreSQL хранится как исходное строковое представление JSON и должно декодироваться при запросе по ключам. Поле jsonb хранится на основе фактической структуры JSON, что позволяет индексировать. Цена — небольшая дополнительная стоимость при записи в поле jsonb. JSONField использует jsonb.

В результате, это поле требует PostgreSQL ≥ 9.4 и Psycopg2 ≥ 2.5.4.

Запросы к полю JSONField

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

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

class Dog(models.Model):
    name = models.CharField(max_length=200)
    data = JSONField()

    def __str__(self):  # __unicode__ on Python 2
        return self.name

Поиск по ключу, индексу и пути

Чтобы выполнить запрос по заданному ключу словаря, просто используйте этот ключ в качестве имени фильтра:

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

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

Несколько ключей могут быть объединены для создания запроса по пути:

>>> Dog.objects.filter(data__owner__name='Bob')
<QuerySet [<Dog: Rufus>]>

Если ключ является целым числом, он будет интерпретирован как поиск по индексу в массиве:

>>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
<QuerySet [<Dog: Rufus>]>

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

Если используется только один ключ или индекс, используется SQL оператор ->. Если используются несколько операторов, используется оператор #>.

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

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

Операции с включением и ключами

JSONField использует те же операции включения и работы с ключами, что и HStoreField.

  • contains (принимает любой JSON, а не только словарь строк)
  • contained_by (принимает любой JSON, а не только словарь строк)
  • has_key
  • has_any_keys
  • has_keys

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

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

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

IntegerRangeField

class IntegerRangeField(**options) [source]

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

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

BigIntegerRangeField

class BigIntegerRangeField(**options) [source]

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

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

FloatRangeField

class FloatRangeField(**options) [source]

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

DateTimeRangeField

class DateTimeRangeField(**options) [source]

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

DateRangeField

class DateRangeField(**options) [source]

Хранит диапазон дат. Основан на 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):  # __unicode__ on Python 2
        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>]>
Новая функция в Django 1.9.

Запрос contained_by также доступен для типов полей без диапазона: IntegerField, BigIntegerField, 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 []>

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

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

class RangeField(**options) [source]

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

base_field

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

range_type

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

form_field

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

class django.contrib.postgres.forms.BaseRangeField

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

base_field

Поле формы для использования.

range_type

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

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

Spec-Zone.ru

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