Отношения сериализаторов
Отношения сериализаторов
Структуры данных, а не алгоритмы, занимают центральное место в программировании.
Реляционные поля используются для представления отношений между моделями. Они могут применяться к отношениям ForeignKey
, ManyToManyField
и OneToOneField
, а также к обратным отношениям и пользовательским отношениям, таким как GenericForeignKey
.
Примечание: Реляционные поля объявляются в relations.py
, но по соглашению вы должны импортировать их из модуля serializers
, используя from rest_framework import serializers
и ссылаться на поля как serializers.<FieldName>
.
Примечание: DRF не пытается автоматически оптимизировать передаваемые сериализаторам наборы запросов в терминах select_related
и prefetch_related
, поскольку это было бы слишком сложной магией. Сериализатор с полем, охватывающим отношение orm через атрибут source, может потребовать дополнительного обращения к базе данных для получения связанных объектов из базы данных. В обязанности программиста входит оптимизация запросов, чтобы избежать дополнительных обращений к базе данных, которые могут возникнуть при использовании такого сериализатора.
Например, следующий сериализатор будет приводить к попаданию в базу данных каждый раз при оценке поля tracks
, если оно не префетчено:
Если AlbumSerializer
используется для сериализации довольно большого набора запросов с many=True
, то это может стать серьезной проблемой производительности. Оптимизация кверисета, передаваемого AlbumSerializer
с:
решит эту проблему.
Инспектирование отношений.
При использовании класса ModelSerializer
, поля и отношения сериализатора будут автоматически сгенерированы для вас. Проверка этих автоматически сгенерированных полей может быть полезным инструментом для определения того, как настроить стиль отношений.
Для этого откройте оболочку Django, используя python manage.py shell
, затем импортируйте класс сериализатора, инстанцируйте его и выведите представление объекта...
API Reference
Для того чтобы объяснить различные типы реляционных полей, мы будем использовать пару простых моделей для наших примеров. Нашими моделями будут музыкальные альбомы и треки, перечисленные в каждом альбоме.
StringRelatedField
StringRelatedField
может использоваться для представления цели отношения с помощью своего метода __str__
.
Например, следующий сериализатор:
Сериализуется в следующее представление:
Это поле доступно только для чтения.
Аргументы:
many
- Если применяется к отношениям типа "ко многим", следует установить этот аргумент вTrue
.
PrimaryKeyRelatedField
PrimaryKeyRelatedField
может использоваться для представления цели отношения с помощью его первичного ключа.
Например, следующий сериализатор:
Сериализуется в представление, подобное этому:
По умолчанию это поле предназначено для чтения-записи, хотя вы можете изменить это поведение с помощью флага read_only
.
Аргументы:
queryset
- Набор запросов, используемый для поиска экземпляра модели при проверке ввода поля. Отношения должны либо явно задать queryset, либо установитьread_only=True
.many
- Если применяется к отношениям типа "ко многим", вы должны установить этот аргумент вTrue
.allow_null
- Если установить значениеTrue
, поле будет принимать значенияNone
или пустую строку для нулевых отношений. По умолчаниюFalse
.pk_field
- Устанавливается в поле для управления сериализацией/десериализацией значения первичного ключа. Например,pk_field=UUIDField(format='hex')
будет сериализовать первичный ключ UUID в его компактное шестнадцатеричное представление.
HyperlinkedRelatedField
HyperlinkedRelatedField
может использоваться для представления цели отношения с помощью гиперссылки.
Например, следующий сериализатор:
Сериализуется в представление, подобное этому:
По умолчанию это поле предназначено для чтения-записи, хотя вы можете изменить это поведение с помощью флага read_only
.
Примечание: Это поле предназначено для объектов, сопоставленных с URL, который принимает один именованный аргумент URL, заданный с помощью аргументов lookup_field
и lookup_url_kwarg
.
Это подходит для URL, которые содержат один первичный ключ или аргумент slug как часть URL.
Если вам требуется более сложное представление гиперссылок, вам необходимо настроить поле, как описано ниже в разделе пользовательские гиперссылочные поля.
Аргументы:
view_name
- Имя представления, которое должно использоваться в качестве цели отношения. Если вы используете стандартные классы маршрутизаторов, это будет строка с форматом<имя модели>-detail
. необходимо.queryset
- Набор запросов, используемый для поиска экземпляра модели при проверке ввода поля. Отношения должны либо явно задать queryset, либо установитьread_only=True
.many
- Если применяется к отношениям типа "ко многим", вы должны установить этот аргумент вTrue
.allow_null
- Если установить значениеTrue
, поле будет принимать значенияNone
или пустую строку для нулевых отношений. По умолчаниюFalse
.lookup_field
- Поле цели, которое должно быть использовано для поиска. Должно соответствовать именованному аргументу URL в ссылающемся представлении. По умолчанию'pk'
.lookup_url_kwarg
- Имя именованного аргумента, определенного в URL conf, который соответствует полю поиска. По умолчанию используется то же значение, что иlookup_field
.format
- Если используются суффиксы формата, то поля с гиперссылками будут использовать тот же суффикс формата для цели, если это не отменено с помощью аргументаformat
.
SlugRelatedField
SlugRelatedField
может использоваться для представления цели отношения с помощью поля цели.
Например, следующий сериализатор:
Сериализуется в представление, подобное этому:
По умолчанию это поле предназначено для чтения-записи, хотя вы можете изменить это поведение с помощью флага read_only
.
При использовании SlugRelatedField
в качестве поля для чтения-записи вы обычно хотите убедиться, что поле slug соответствует полю модели с unique=True
.
Аргументы:
slug_field
- Поле цели, которое должно быть использовано для ее представления. Это должно быть поле, которое однозначно идентифицирует любой данный экземпляр. Например,username
. обязательноqueryset
- Набор запросов, используемый для поиска экземпляра модели при проверке ввода поля. Отношения должны либо явно задать queryset, либо установитьread_only=True
.many
- Если применяется к отношениям типа "ко многим", вы должны установить этот аргумент вTrue
.allow_null
- Если установить значениеTrue
, поле будет принимать значенияNone
или пустую строку для нулевых отношений. По умолчанию установлено значениеFalse
.
HyperlinkedIdentityField
Это поле может применяться как отношение идентичности, например, поле 'url'
в HyperlinkedModelSerializer
. Оно также может быть использовано для атрибута объекта. Например, следующий сериализатор:
Сериализуется в представление, подобное этому:
Это поле всегда доступно только для чтения.
Аргументы:
view_name
- Имя представления, которое должно использоваться в качестве цели отношения. Если вы используете стандартные классы маршрутизаторов, это будет строка с форматом<имя_модели>-detail
. необходимо.lookup_field
- Поле цели, которое должно быть использовано для поиска. Должно соответствовать именованному аргументу URL в ссылающемся представлении. По умолчанию'pk'
.lookup_url_kwarg
- Имя именованного слова, определенного в URL conf, который соответствует полю поиска. По умолчанию используется то же значение, что иlookup_field
.format
- Если используются суффиксы формата, поля с гиперссылками будут использовать тот же суффикс формата для цели, если это не будет отменено с помощью аргументаformat
.
Вложенные отношения
В отличие от ранее рассмотренных ссылок на другую сущность, ссылающаяся сущность может быть встроена или вложена в представление объекта, который на нее ссылается. Такие вложенные отношения могут быть выражены с помощью сериализаторов в качестве полей.
Если поле используется для представления отношения "ко многим", необходимо добавить флаг many=True
к полю сериализатора.
Пример
Например, следующий сериализатор:
Сериализуется во вложенное представление следующим образом:
Записываемые вложенные сериализаторы
По умолчанию вложенные сериализаторы доступны только для чтения. Если вы хотите поддерживать операции записи во вложенное поле сериализатора, вам необходимо создать методы create()
и/или update()
, чтобы явно указать, как должны сохраняться дочерние отношения:
Пользовательские реляционные поля
В редких случаях, когда ни один из существующих реляционных стилей не подходит для нужного вам представления, вы можете реализовать полностью пользовательское реляционное поле, которое описывает, как именно должно быть сгенерировано выходное представление из экземпляра модели.
Для реализации пользовательского реляционного поля необходимо переопределить RelatedField
и реализовать метод .to_representation(self, value)
. Этот метод принимает цель поля в качестве аргумента value
и должен возвращать представление, которое должно использоваться для сериализации цели. Аргумент value
обычно представляет собой экземпляр модели.
Если вы хотите реализовать реляционное поле для чтения и записи, вы должны также реализовать метод .to_internal_value(self, data)
.
Чтобы обеспечить динамический набор запросов, основанный на context
, вы также можете переопределить .get_queryset(self)
вместо указания .queryset
в классе или при инициализации поля.
Пример
Например, мы можем определить реляционное поле для сериализации трека в пользовательское строковое представление, используя его порядок, название и продолжительность:
Это пользовательское поле затем сериализуется в следующее представление:
Пользовательские поля с гиперссылками
В некоторых случаях вам может понадобиться настроить поведение поля с гиперссылкой, чтобы представить URL-адреса, для которых требуется более одного поля поиска.
Вы можете добиться этого, переопределив HyperlinkedRelatedField
. Есть два метода, которые могут быть переопределены:
get_url(self, obj, view_name, request, format).
Метод get_url
используется для сопоставления экземпляра объекта с его URL-представлением.
Может вызвать ошибку NoReverseMatch
, если атрибуты view_name
и lookup_field
не настроены на правильное соответствие URL conf.
get_object(self, view_name, view_args, view_kwargs).
Если вы хотите поддерживать записываемое поле с гиперссылками, вам также потребуется переопределить get_object
, чтобы сопоставить входящие URL обратно с объектом, который они представляют. Для полей с гиперссылками, доступных только для чтения, нет необходимости переопределять этот метод.
Возвращаемое значение этого метода - объект, соответствующий аргументам URL conf.
Может вызвать исключение ObjectDoesNotExist
.
Пример
Допустим, у нас есть URL для объекта customer, который принимает два аргумента в виде ключевых слов, как показано ниже:
Это не может быть представлено с помощью реализации по умолчанию, которая принимает только одно поле поиска.
В этом случае нам нужно переопределить HyperlinkedRelatedField
, чтобы получить желаемое поведение:
Обратите внимание, что если вы хотите использовать этот стиль вместе с общими представлениями, то вам также необходимо переопределить .get_object
в представлении, чтобы получить правильное поведение поиска.
Обычно мы рекомендуем использовать плоский стиль для представления API, когда это возможно, но вложенный стиль URL также может быть разумным при умеренном использовании.
Дальнейшие примечания
Аргумент queryset
.
queryset
.Аргумент queryset
требуется только для записываемого поля отношения, в этом случае он используется для выполнения поиска экземпляра модели, который отображает примитивный пользовательский ввод в экземпляр модели.
В версии 2.x класс сериализатора мог иногда автоматически определять аргумент queryset
, если использовался класс ModelSerializer
.
Теперь это поведение заменено на всегда использование явного аргумента queryset
для записываемых реляционных полей.
Это уменьшает количество скрытой "магии", которую обеспечивает ModelSerializer
, делает поведение поля более понятным и гарантирует, что можно легко переходить от использования ярлыка ModelSerializer
к использованию полностью явных классов Serializer
.
Настройка отображения HTML
Встроенный метод __str__
модели будет использоваться для создания строковых представлений объектов, используемых для заполнения свойства choices
. Эти варианты используются для заполнения HTML-вводов выбора в Web-интерфейсе API.
Чтобы обеспечить настраиваемое представление для таких входов, переопределите display_value()
подкласса RelatedField
. Этот метод получит объект модели и должен вернуть строку, подходящую для его представления. Например:
Выберите отсечение полей
При отображении в Web-интерфейсе API реляционные поля по умолчанию будут отображать не более 1000 элементов для выбора. Если элементов больше, то будет отображаться отключенная опция 'More than 1000 items...'
.
Это поведение предназначено для того, чтобы предотвратить невозможность отрисовки шаблона за приемлемое время из-за отображения очень большого количества связей.
Есть два именованных аргумента, которые можно использовать для управления этим поведением:
html_cutoff
- Если установлено, это будет максимальное количество вариантов выбора, которое будет отображаться в выпадающем списке HTML select. Установите значениеNone
, чтобы отключить любое ограничение. По умолчанию1000
.html_cutoff_text
- При установке этого параметра будет отображаться текстовый индикатор, если максимальное количество элементов было отсечено в выпадающем списке HTML select. По умолчанию'More than {count} items...'
.
Вы также можете управлять ими глобально, используя настройки HTML_SELECT_CUTOFF
и HTML_SELECT_CUTOFF_TEXT
.
В случаях, когда отсечение вводится принудительно, вы можете использовать обычное поле ввода в HTML-форме. Вы можете сделать это, используя именованный аргумент style
. Например:
Обратные отношения
Обратите внимание, что обратные отношения не включаются автоматически классами ModelSerializer
и HyperlinkedModelSerializer
. Чтобы включить обратное отношение, вы должны явно добавить его в список полей. Например:
Обычно вам нужно убедиться, что вы установили соответствующий аргумент related_name
для отношения, который вы можете использовать в качестве имени поля. Например:
Если вы не задали связанное имя для обратного отношения, вам придется использовать автоматически сгенерированное связанное имя в аргументе fields
. Например:
Более подробную информацию смотрите в документации Django по обратным отношениям.
Общие отношения
Если вы хотите сериализовать общий внешний ключ, вам необходимо определить пользовательское поле, чтобы явно определить, как вы хотите сериализовать цели отношения.
Например, дана следующая модель для тега, которая имеет общие отношения с другими произвольными моделями:
И следующие две модели, которые могут иметь связанные теги:
Мы можем определить пользовательское поле, которое будет использоваться для сериализации помеченных экземпляров, используя тип каждого экземпляра для определения того, как он должен быть сериализован:
Если вам нужно, чтобы цель отношения имела вложенное представление, вы можете использовать необходимые сериализаторы внутри метода .to_representation()
:
Обратите внимание, что обратные родовые ключи, выраженные с помощью поля GenericRelation
, могут быть сериализованы с использованием обычных типов реляционных полей, поскольку тип цели в отношениях всегда известен.
Для получения дополнительной информации смотрите документацию Django по общим отношениям.
ManyToManyFields со сквозной моделью
По умолчанию реляционные поля, нацеленные на ManyToManyField
с указанной моделью through
, устанавливаются только для чтения.
Если вы явно указываете реляционное поле, указывающее на ManyToManyField
со сквозной моделью, обязательно установите read_only
в True
.
Если вы хотите представить дополнительные поля в сквозной модели, то вы можете сериализовать сквозную модель как вложенный объект.
Сторонние пакеты
Также доступны следующие пакеты сторонних производителей.
DRF nested routers
Пакет drf-nested-routers предоставляет маршрутизаторы и поля отношений для работы с вложенными ресурсами.
Rest Framework Generic Relations
Библиотека rest-framework-generic-relations обеспечивает сериализацию чтения/записи для общих внешних ключей.
Last updated