Официальная оригинальная ссылка
Эта серия статей адрес github
Пожалуйста, укажите источник
Связь сериализатора
Поля отношений используются для представления отношений модели. они могут быть применены кForeignKey
,ManyToManyField
иOneToOneField
отношения, обратные отношения иGenericForeignKey
и другие пользовательские отношения.
Уведомление:Поле отношений находится в
relations.py
заявление, но по соглашению вы должны начать сserializers
модули импортируют их, используяfrom rest_framework import serializers
импортировать и т.п.serializers.<FieldName>
Поля ссылаются следующим образом.
Проверьте отношения.
в настоящее время используетModelSerializer
класс, сериализованные поля и отношения автоматически генерируются для вас. Просмотрите эти автоматически сгенерированные поля, чтобы узнать, как настроить стиль отношений.
Для этого используйтеpython manage.py shell
Откройте оболочку Django, затем импортируйте класс сериализации, создайте его экземпляр и распечатайте представление объекта...
>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print repr(serializer) # Or `print(repr(serializer))` in Python 3.x.
AccountSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(allow_blank=True, max_length=100, required=False)
owner = PrimaryKeyRelatedField(queryset=User.objects.all())
Справочник по API
Чтобы объяснить различные типы реляционных полей, мы будем использовать несколько простых моделей для нашего примера. В нашей модели будут использоваться музыкальные альбомы и треки, перечисленные в каждом альбоме.
class Album(models.Model):
album_name = models.CharField(max_length=100)
artist = models.CharField(max_length=100)
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
order = models.IntegerField()
title = models.CharField(max_length=100)
duration = models.IntegerField()
class Meta:
unique_together = ('album', 'order')
ordering = ['order']
def __unicode__(self):
return '%d: %s' % (self.order, self.title)
StringRelatedField
StringRelatedField
для использования__unicode__
Методы представляют отношения.
Например, класс сериализации ниже.
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
сериализуется в следующую форму.
{
'album_name': 'Things We Lost In The Fire',
'artist': 'Low',
'tracks': [
'1: Sunflower',
'2: Whitetail',
'3: Dinosaur Act',
...
]
}
Это поле доступно только для чтения.
параметр:
-
many
- Если это отношение «один ко многим», установите для этого параметра значениеTrue
.
PrimaryKeyRelatedField
PrimaryKeyRelatedField
Используется для представления отношения с помощью его первичного ключа.
Например, следующий класс сериализации:
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
будет сериализоваться в такое представление:
{
'album_name': 'Undun',
'artist': 'The Roots',
'tracks': [
89,
90,
91,
...
]
}
По умолчанию поле доступно для чтения и записи, но вы можете использоватьread_only
флаг, чтобы изменить это поведение.
параметр:
-
queryset
- Набор запросов для использования в запросах экземпляра модели при проверке ввода в поле. Набор запросов должен быть установлен явно или установленread_only=True
. -
many
- Если применяется к отношению "один ко многим", этот параметр должен быть установлен вTrue
. -
allow_null
- если установленоTrue
, то поле приметNone
Значение или пустая строка для отношения, допускающего значение NULL. По умолчаниюFalse
. -
pk_field
- Установить как поле для управления сериализацией/десериализацией значений первичного ключа. Например,pk_field=UUIDField(format='hex')
Первичный ключ UUID сериализуется в его компактное шестнадцатеричное представление.
HyperlinkedRelatedField
HyperlinkedRelatedField
Используется для выражения отношений с помощью гиперссылок.
Например, следующий класс сериализации:
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name='track-detail'
)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
будет сериализоваться в такое представление:
{
'album_name': 'Graceland',
'artist': 'Paul Simon',
'tracks': [
'http://www.example.com/api/tracks/45/',
'http://www.example.com/api/tracks/46/',
'http://www.example.com/api/tracks/47/',
...
]
}
По умолчанию поле доступно для чтения и записи, но вы можете использоватьread_only
флаг, чтобы изменить это поведение.
Уведомление: это поле предназначено для объектов, которые сопоставляются с URL-адресами, которые принимают один аргумент ключевого слова URL-адреса, например, использованиеlookup_field
иlookup_url_kwarg
Объект настройки параметров.
Это работает для URL-адресов, которые содержат один первичный ключ или параметр slug как часть URL-адреса.
Если вам нужно более сложное представление гиперссылки, вам нужно настроить это поле, что будет объяснено позже.
параметр:
-
view_name
- Имя представления для использования в качестве цели отношения. Если вы используете стандартный класс маршрутизатора, это будет формат<modelname>-detail
Нить.необходимые. -
queryset
- Набор запросов для использования в запросах экземпляра модели при проверке ввода в поле. Набор запросов должен быть установлен явно или установленread_only=True
. -
many
- Если применяется к отношению "один ко многим", этот параметр должен быть установлен вTrue
. -
allow_null
- если установленоTrue
, то поле приметNone
Значение или пустая строка для отношения, допускающего значение NULL. По умолчаниюFalse
. -
lookup_field
- Целевое поле для поиска. Соответствует аргументам ключевого слова URL в представлении ссылки. По умолчанию'pk'
. -
lookup_url_kwarg
- Имя аргумента ключевого слова, определенного в конфигурации URL, соответствующей полю поиска. По умолчанию используется сlookup_field
такое же значение. -
format
- Если используется суффикс формата, поле гиперссылки будет использовать тот же суффикс формата, что и цель, если не используетсяformat
параметры переопределены.
SlugRelatedField
SlugRelatedField
Используется для представления отношений с использованием полей в цели.
Например, следующий класс сериализации:
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='title'
)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
будет сериализоваться в такое представление:
{
'album_name': 'Dear John',
'artist': 'Loney Dear',
'tracks': [
'Airport Surroundings',
'Everything Turns to You',
'I Was Only Going Out',
...
]
}
По умолчанию поле доступно для чтения и записи, но вы можете использоватьread_only
флаг, чтобы изменить это поведение.
будетSlugRelatedField
При использовании в качестве поля для чтения и записи обычно необходимо убедиться, что поле slug соответствуетunique=True
соответствующие полям модели.
параметр:
-
slug_field
- Поле, используемое для представления цели. Это должно быть поле, которое однозначно идентифицирует данный экземпляр. Например,username
.необходимые -
queryset
- Набор запросов для использования в запросах экземпляра модели при проверке ввода в поле. Набор запросов должен быть установлен явно или установленread_only=True
. -
many
- Если применяется к отношению "один ко многим", этот параметр должен быть установлен вTrue
. -
allow_null
- если установленоTrue
, то поле приметNone
Значение или пустая строка для отношения, допускающего значение NULL. По умолчаниюFalse
.
HyperlinkedIdentityField
Это поле может применяться как отношение идентичности, например.HyperlinkedModelSerializer
Вверх'url'
поле. Его также можно использовать для свойств объектов. Например, следующий класс сериализации:
class AlbumSerializer(serializers.HyperlinkedModelSerializer):
track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')
class Meta:
model = Album
fields = ('album_name', 'artist', 'track_listing')
будет сериализоваться в такое представление:
{
'album_name': 'The Eraser',
'artist': 'Thom Yorke',
'track_listing': 'http://www.example.com/api/track_list/12/',
}
Это поле всегда доступно только для чтения.
параметр:
-
view_name
- Имя представления для использования в качестве цели отношения. Если вы используете стандартный класс маршрутизатора, это будет формат<modelname>-detail
Нить.необходимые. -
lookup_field
- Целевое поле для поиска. Соответствует аргументам ключевого слова URL в ссылочном представлении. По умолчанию'pk'
. -
lookup_url_kwarg
- Имя аргумента ключевого слова, определенного в конфигурации URL, соответствующей полю поиска. По умолчанию используется сlookup_field
такое же значение. -
format
- Если используется суффикс формата, поле гиперссылки будет использовать тот же суффикс формата, что и цель, если не используетсяformat
параметры переопределены.
вложенные отношения
Вложенные отношения можно выразить с помощью сериализованных классов в качестве полей.
Если поле используется для представления отношения «один ко многим», оно должно бытьmany=True
Флаги добавляются к сериализованным полям.
взять каштан
Например, следующий класс сериализации:
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('order', 'title', 'duration')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
будет сериализоваться во вложенное представление следующим образом:
>>> album = Album.objects.create(album_name="The Grey Album", artist='Danger Mouse')
>>> Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245)
<Track: Track object>
>>> Track.objects.create(album=album, order=2, title='What More Can I Say', duration=264)
<Track: Track object>
>>> Track.objects.create(album=album, order=3, title='Encore', duration=159)
<Track: Track object>
>>> serializer = AlbumSerializer(instance=album)
>>> serializer.data
{
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
...
],
}
Доступный для записи вложенный класс сериализации
Вложенные классы сериализации по умолчанию доступны только для чтения. Если вы хотите поддерживать запись во вложенные сериализованные поля, вам необходимо создатьcreate()
и/илиupdate()
чтобы явно указать, как следует сохранять дочерние отношения.
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('order', 'title', 'duration')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
>>> data = {
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
],
}
>>> serializer = AlbumSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()
<Album: Album object>
Пользовательские поля отношений
В редком случае, когда ни один из существующих типов отношений не соответствует нужному представлению, вы можете реализовать полностью настраиваемое поле отношения, которое точно описывает, как выходное представление должно быть сгенерировано из экземпляра модели.
Чтобы реализовать настраиваемые поля отношений, вы должны переопределитьRelatedField
, и реализовать.to_representation(self, value)
метод. Этот метод принимает цель поля какvalue
параметры и возвращает представление, примененное к сериализованной цели.value
Параметр обычно является экземпляром модели.
Если вы хотите реализовать реляционные поля для чтения и записи, вы также должны реализовать.to_internal_value(self, data)
метод.
предоставлять на основеcontext
динамические наборы запросов, вы также можете переопределить.get_queryset(self)
, вместо указания в классе.queryset
или инициализировать поле.
взять каштан
Например, мы можем определить реляционное поле для сериализации звуковой дорожки в пользовательское строковое представление, используя ее порядок, название и продолжительность.
import time
class TrackListingField(serializers.RelatedField):
def to_representation(self, value):
duration = time.strftime('%M:%S', time.gmtime(value.duration))
return 'Track %d: %s (%s)' % (value.order, value.name, duration)
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackListingField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
будет сериализоваться в такое представление:
{
'album_name': 'Sometimes I Wish We Were an Eagle',
'artist': 'Bill Callahan',
'tracks': [
'Track 1: Jim Cain (04:39)',
'Track 2: Eid Ma Clack Shaw (04:19)',
'Track 3: The Wind and the Dove (04:34)',
...
]
}
пользовательское поле гиперссылки
В некоторых случаях может потребоваться настроить поведение полей гиперссылок для представления URL-адресов, для которых требуется несколько полей запроса.
Вы можете унаследоватьHyperlinkedRelatedField
для достижения этой цели. Есть два метода, которые можно переопределить:
get_url(self, obj, view_name, request, format)
get_url
Методы используются для сопоставления экземпляров объектов с их представлениями URL.
еслиview_name
иlookup_field
Свойства не настроены для правильного соответствия конфигурации URL, могутNoReverseMatch
.
get_object(self, queryset, view_name, view_args, view_kwargs)
Если вы хотите поддерживать доступные для записи поля гиперссылок, вам также необходимо переопределитьget_object
, чтобы сопоставить входящие URL-адреса с объектами, которые они представляют. Для полей гиперссылок, доступных только для чтения, этот метод не нужно переопределять.
Возвращаемым значением этого метода должен быть объект, соответствующий соответствующему параметру конфигурации URL.
может привести кObjectDoesNotExist
аномальный.
взять каштан
Предположим, у нас есть URL-адрес объекта клиента с двумя ключевыми словами, например:
/api/<organization_slug>/customers/<customer_pk>/
Это не может быть представлено реализацией по умолчанию, которая принимает только одно поле поиска.
В этом случае нам нужно наследоватьHyperlinkedRelatedField
и переопределить методы в нем, чтобы получить желаемое поведение:
from rest_framework import serializers
from rest_framework.reverse import reverse
class CustomerHyperlink(serializers.HyperlinkedRelatedField):
# We define these as class attributes, so we don't need to pass them as arguments.
view_name = 'customer-detail'
queryset = Customer.objects.all()
def get_url(self, obj, view_name, request, format):
url_kwargs = {
'organization_slug': obj.organization.slug,
'customer_pk': obj.pk
}
return reverse(view_name, kwargs=url_kwargs, request=request, format=format)
def get_object(self, view_name, view_args, view_kwargs):
lookup_kwargs = {
'organization__slug': view_kwargs['organization_slug'],
'pk': view_kwargs['customer_pk']
}
return self.get_queryset().get(**lookup_kwargs)
Обратите внимание: если вы хотите использовать этот стиль с общим представлением, вам также потребуется переопределить.get_object
чтобы получить правильное поведение поиска.
В общем, мы рекомендуем использовать плоский стиль для представления API, когда это возможно, но стиль вложенных URL-адресов также разумен при умеренном использовании.
Дальнейшее объяснение
queryset
параметр
queryset
Этот параметр требуется только для доступных для записи реляционных полей, и в этом случае он используется для выполнения поиска экземпляра модели, который сопоставляет базовый пользовательский ввод с экземпляром модели.
В версии 2.x, если вы используетеModelSerializer
класс, класс сериализации иногда определяется автоматическиqueryset
параметр.
Это поведение теперь заменено на всегда использовать явное для реляционных полей, доступных для записи.queryset
параметр.
Это снижаетModelSerializer
Количество предоставленной скрытой «магии» (имеется в видуModelSerializer
работать на нас внутри), чтобы сделать поведение полей более понятным и гарантировать, что при использованииModelSerializer
Ярлыки (высоко инкапсулированные, простые в использовании) или используйте полностью явныеSerializer
Преобразование между классами тривиально.
пользовательское отображение HTML
модель встроенная__str__
метод, используемый для созданияchoices
Строковое представление объекта свойства. Эти варианты используются для заполнения выбранных входных данных HTML в доступном для просмотра API.
Чтобы предоставить пользовательские представления для этих входных данных, переопределитеRelatedField
подклассdisplay_value()
метод. Этот метод получит объект модели и должен вернуть строку, подходящую для его представления. Например:
class TrackPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
def display_value(self, instance):
return 'Track: %s' % (instance.title)
Select field cutoffs
При отображении просматриваемых полей отношений API по умолчанию отображается не более 1000 необязательных элементов. Если элементов больше, отображается отключенная опция «Более 1000 элементов…».
Это поведение предназначено для предотвращения отображения шаблона в приемлемые сроки из-за большого количества отображаемых взаимосвязей.
Есть два аргумента ключевого слова, которые можно использовать для управления этим поведением:
-
html_cutoff
- Устанавливает максимальное количество параметров, отображаемых в раскрывающемся списке выбора HTML. Установить какNone
Любое ограничение можно отключить. По умолчанию1000
. -
html_cutoff_text
- Устанавливает текстовую строку для отображения, когда раскрывающийся список выбора HTML превышает максимальный размер экрана. По умолчанию"More than {count} items…"
Вы также можете использовать в настройкахHTML_SELECT_CUTOFF
иHTML_SELECT_CUTOFF_TEXT
для глобального управления этими настройками.
В случаях, когда применяется отсечение, вместо этого вы можете использовать простые поля ввода в HTML-формах. ты можешь использоватьstyle
аргументы ключевого слова, чтобы сделать это. Например:
assigned_to = serializers.SlugRelatedField(
queryset=User.objects.all(),
slug_field='username',
style={'base_template': 'input.html'}
)
Обратная зависимость
Обратите внимание, что обратные отношения не включаются автоматически вModelSerializer
иHyperlinkedModelSerializer
в классе. Чтобы включить обратное отношение, вы должны явно добавить его в список полей. Например:
class AlbumSerializer(serializers.ModelSerializer):
class Meta:
fields = ('tracks', ...)
Часто бывает необходимо убедиться, что для отношения были сделаны соответствующие настройки.related_name
параметр, который можно использовать в качестве имени поля. Например:
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
...
Если вы не задали корреляционное имя для обратной связи, вам нужноfields
Используйте автоматически сгенерированное имя корреляции в параметре. Например:
class AlbumSerializer(serializers.ModelSerializer):
class Meta:
fields = ('track_set', ...)
родовые отношения
Если вы хотите сериализовать общий внешний ключ, вам нужно настраиваемое поле, которое явно определяет, как сериализовать отношение.
Например, дана метка для следующей модели, которая имеет общее отношение к любой другой модели:
class TaggedItem(models.Model):
"""
Tags arbitrary model instances using a generic relation.
See: https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/
"""
tag_name = models.SlugField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
tagged_object = GenericForeignKey('content_type', 'object_id')
def __unicode__(self):
return self.tag_name
Следующие два режима могут использовать связанные теги:
class Bookmark(models.Model):
"""
A bookmark consists of a URL, and 0 or more descriptive tags.
"""
url = models.URLField()
tags = GenericRelation(TaggedItem)
class Note(models.Model):
"""
A note consists of some text, and 0 or more descriptive tags.
"""
text = models.CharField(max_length=1000)
tags = GenericRelation(TaggedItem)
Мы можем определить настраиваемое поле, которое можно использовать для сериализации экземпляров тега, и использовать тип каждого экземпляра, чтобы определить, как его следует сериализовать.
class TaggedObjectRelatedField(serializers.RelatedField):
"""
A custom field to use for the `tagged_object` generic relationship.
"""
def to_representation(self, value):
"""
Serialize tagged objects to a simple textual representation.
"""
if isinstance(value, Bookmark):
return 'Bookmark: ' + value.url
elif isinstance(value, Note):
return 'Note: ' + value.text
raise Exception('Unexpected type of tagged object')
Если отношение, которое вам нужно, имеет вложенное представление, вы можете.to_representation()
Требуемый класс сериализации используется в методе:
def to_representation(self, value):
"""
Serialize bookmark instances using a bookmark serializer,
and note instances using a note serializer.
"""
if isinstance(value, Bookmark):
serializer = BookmarkSerializer(value)
elif isinstance(value, Note):
serializer = NoteSerializer(value)
else:
raise Exception('Unexpected type of tagged object')
return serializer.data
Обратите внимание, что использованиеGenericRelation
Обратный универсальный ключ, представленный полем, может быть сериализован с использованием обычного реляционного типа поля, поскольку тип цели в отношении всегда известен.
ManyToManyFields со сквозной моделью
По умолчанию он будет указан сthrough
модельManyToManyField
Поле отношения доступно только для чтения.
Если бы вы явно указали указатель на модель со сквознымManyToManyField
поля отношения, обязательно установитеread_only
Установить какTrue
.