Spec-Zone.ru › Django 1.9

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

Если требуются непрямоугольные формы, тогда базовое поле должно быть сделано nullable, а значения дополнены 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'])
[<Post: First post>, <Post: Second post>]

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

>>> Post.objects.filter(tags__contains=['django', 'thoughts'])
[<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'])
[<Post: First post>, <Post: Second post>]

>>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial'])
[<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'])
[<Post: First post>, <Post: Second post>]

>>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
[<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)
[<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')
[<Post: First post>, <Post: Second post>]

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

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

Примечание

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'])
[<Post: First post>, <Post: Second post>]

>>> Post.objects.filter(tags__0_2__contains=['thoughts'])
[<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 перед первой операцией CreateModel или AddField добавив миграцию с помощью операции HStoreExtension. Например:

    from django.contrib.postgres.operations import HStoreExtension
    
    class Migration(migrations.Migration):
        ...
    
        operations = [
            HStoreExtension(),
            ...
        ]
    

    Для создания расширения требуется пользователь базы данных с привилегиями superuser. Если пользователь Django базы данных не обладает привилегиями superuser, вам придется создать расширение вне миграций Django с пользователем, имеющим соответствующие привилегии. В этом случае подключитесь к базе данных Django и выполните запрос CREATE EXTENSION IF NOT EXISTS hstore;

Вы увидите ошибку, похожую на 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')
[<Dog: Meg>]

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

>>> Dog.objects.filter(data__breed__contains='l')
[<Dog: Rufus>, <Dog: Meg>]

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

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

Поскольку любой строкой может быть ключ в значении 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'})
[<Dog: Rufus>, <Dog: Meg>]

>>> Dog.objects.filter(data__contains={'breed': 'collie'})
[<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'})
[<Dog: Meg>, <Dog: Fred>]

>>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
[<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')
[<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'])
[<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'])
[<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'])
[<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'])
[<Dog: Meg>]

JSONField

class JSONField(**options) [source]

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

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

Если для поля задано default, убедитесь, что это вызываемый объект, например 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')
[<Dog: Meg>]

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

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

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

>>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
[<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 и в Python как NumericRange.

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

BigIntegerRangeField

class BigIntegerRangeField(**options) [source]

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

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

FloatRangeField

class FloatRangeField(**options) [source]

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

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))
[<Event: Soft play>]
contained_by
>>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
[<Event: Soft play>]

Запрос 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),
... )
[<Event: Soft play>]
overlap
>>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
[<Event: Soft play>]

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

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

fully_lt

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

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

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

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

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

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

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

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

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

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

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

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

startswith

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

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

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

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

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

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

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

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.9/ref/contrib/postgres/fields/

Spec-Zone.ru

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