Руководство по API платформы Django REST (1): запросы
Руководство по API платформы Django REST (2): ответы
Руководство по API платформы Django REST (3): представления
Руководство по API платформы Django REST (4): общие представления
Руководство по API платформы Django REST (5): наборы представлений
Руководство по API Django REST framework (6): Маршрутизация
Руководство по API платформы Django REST (7): анализ
Руководство по API Django REST framework (8): рендеринг
Руководство по API платформы Django REST (9): Сериализация
Serializers
Сериализаторы позволяют преобразовывать сложные данные, такие как наборы запросов и экземпляры моделей, в собственные типы данных Python, которые затем можно легко представить какJSON
,XML
или другие типы контента. Сериализатор также обеспечивает десериализацию, которая может преобразовать проанализированные данные обратно в сложный тип после предварительной проверки входящих данных.
Классы сериализации в среде REST и DjangoForm
иModelForm
Классы очень похожи. мы предоставляемSerializer
класс, который предоставляет мощный общий способ управления выводом ответа, иModelSerializer
класс, предоставляющий эффективные ярлыки для создания сериализаций, обрабатывающих экземпляры моделей и наборы запросов.
Объявить класс сериализации
Сначала создайте простой объект для примера:
from datetime import datetime
class Comment(object):
def __init__(self, email, content, created=None):
self.email = email
self.content = content
self.created = created or datetime.now()
comment = Comment(email='leila@example.com', content='foo bar')
Объявите класс сериализации, используйте его для сериализации и десериализации с помощьюComment
Данные, соответствующие объекту.
Объявление класса сериализации очень похоже на объявление формы:
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
сериализованный объект
теперь доступноCommentSerializer
сериализовать комментарий или список комментариев. Аналогичным образом используйтеSerializer
Класс очень похож на использованиеForm
своего рода.
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
На данный момент экземпляр модели был преобразован в собственный тип данных Python. Чтобы завершить процесс сериализации, отобразите данные какjson
.
from rest_framework.renderers import JSONRenderer
json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
десериализовать объект
Десериализация аналогична. Сначала мы анализируем поток в собственный тип данных Python...
from django.utils.six import BytesIO
from rest_framework.parsers import JSONParser
stream = BytesIO(json)
data = JSONParser().parse(stream)
... затем мы восстанавливаем эти собственные типы данных в проверенный словарь данных.
serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
сохранить экземпляр
Если вы хотите иметь возможность возвращать полный экземпляр объекта на основе проверенных данных, вам необходимо реализовать.create()
и.update()
один или оба метода. Например:
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
def create(self, validated_data):
return Comment(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
return instance
Если экземпляр объекта соответствует модели Django, вам также необходимо убедиться, что эти методы сохраняют объект в базе данных. еслиComment
является моделью Django, методы могут выглядеть так:
def create(self, validated_data):
return Comment.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance
Теперь при десериализации данных мы можем вызвать.save()
Возвращает экземпляр объекта на основе проверенных данных.
comment = serializer.save()
перечислить.save()
Будет создан новый экземпляр или обновлен существующий экземпляр, в зависимости от того, был ли передан существующий экземпляр при создании экземпляра сериализованного класса:
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
.create()
и.update()
методы необязательны. Вы можете не реализовывать ни то, ни другое, или одно, или оба, в зависимости от варианта использования вашего класса сериализации.
Передать дополнительные свойства в.save()
Иногда вам может понадобиться, чтобы ваш код представления мог вводить дополнительные данные при сохранении экземпляра. Эти дополнительные данные могут содержать текущего пользователя, текущее время или любую другую информацию, которая не является частью запрошенных данных.
serializer.save(owner=request.user)
перечислить.create()
или.update()
, любые другие аргументы ключевого слова будут включены вvalidated_data
в параметре.
прямое покрытие.save()
.
При определенных обстоятельствах,.create()
и.update()
Названия методов могут не иметь смысла. Например, в «контактной форме» мы можем не создавать новый экземпляр, а отправить электронное письмо или другое сообщение.
В этих случаях есть возможность напрямую переопределить.save()
, так как это более читабельно и осмысленно.
Возьмите каштан:
class ContactForm(serializers.Serializer):
email = serializers.EmailField()
message = serializers.CharField()
def save(self):
email = self.validated_data['email']
message = self.validated_data['message']
send_email(from=email, message=message)
Обратите внимание, что в приведенном выше случае прямой доступ должен бытьserializer .validated_data
Атрибуты.
проверять
При десериализации данных вам всегда нужно звонить, прежде чем пытаться получить доступ к данным проверки.is_valid()
или сохраните экземпляр объекта. Если возникают какие-либо ошибки проверки, то.errors
Свойство будет содержать словарь, представляющий сообщение об ошибке. Например:
serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}
Каждый ключ в словаре — это имя поля, а значение — это сообщение об ошибке (список строк), соответствующее этому полю.non_field_errors
Ключ также может присутствовать, и будут перечислены все общие ошибки проверки. можно использоватьNON_FIELD_ERRORS_KEY
(устанавливается в файле настроек) для настройкиnon_field_errors
Название ключевого слова.
При десериализации списка элементов ошибки возвращаются в виде списка словарей, представляющих каждый десериализованный элемент.
Исключение возникло во время проверки данных
.is_valid()
метод с необязательнымraise_exception
Флаг, который заставит его бросить, если есть ошибки проверкиserializers.ValidationError
аномальный.
Эти исключения автоматически обрабатываются обработчиком исключений по умолчанию, предоставляемым инфраструктурой REST, и возвращаются по умолчанию.HTTP 400 Bad Request
.
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
Проверка на уровне поля
ты можешь пройтиSerializer
добавить подкласс.validate_<field_name>
метод для указания пользовательской проверки на уровне поля. Они такие же, как в форме Django..clean_<field_name>
Метод аналогичен.
Эти методы имеют только один параметр — значение поля, которое необходимо проверить.
Вашvalidate_<field_name>
Метод должен возвращать значение проверки или бросатьserializers.ValidationError
.
Например:
from rest_framework import serializers
class BlogPostSerializer(serializers.Serializer):
title = serializers.CharField(max_length=100)
content = serializers.CharField()
def validate_title(self, value):
"""
Check that the blog post is about Django.
"""
if 'django' not in value.lower():
raise serializers.ValidationError("Blog post is not about Django")
return value
Примечание: если ваш сериализатор объявляет
<field_name>
Параметрыrequired = False
, то этот шаг проверки не будет выполнен, если поле не включено.
Проверка на уровне объекта
Если вы хотите выполнить дополнительную проверку нескольких полей, добавьте поле с именем.validate()
способ добавить в свойSerializer
в подклассе. Этот метод имеет только один параметр, который является значением поля (field
-value
) Словарь. При необходимости следует поднятьValidationError
или просто верните проверенное значение. Например:
from rest_framework import serializers
class EventSerializer(serializers.Serializer):
description = serializers.CharField(max_length=100)
start = serializers.DateTimeField()
finish = serializers.DateTimeField()
def validate(self, data):
"""
Check that the start is before the stop.
"""
if data['start'] > data['finish']:
raise serializers.ValidationError("finish must occur after start")
return data
валидатор
Отдельные поля в сериализаторе могут содержать валидаторы, объявляя их в экземпляре поля, например:
def multiple_of_ten(value):
if value % 10 != 0:
raise serializers.ValidationError('Not a multiple of ten')
class GameRecord(serializers.Serializer):
score = IntegerField(validators=[multiple_of_ten])
...
Классы сериализации также могут содержать повторно используемые средства проверки, которые применяются ко всему набору данных полей. Эти валидаторы являются внутреннимиMeta
Они включаются путем объявления их в классе следующим образом:
class EventSerializer(serializers.Serializer):
name = serializers.CharField()
room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
date = serializers.DateField()
class Meta:
# Each room only has one event per day.
validators = UniqueTogetherValidator(
queryset=Event.objects.all(),
fields=['room_number', 'date']
)
Не беда, если вы этого не понимаете, подробнее о верификации поговорим позже.
Доступ к исходным данным и экземплярам
При передаче начального объекта или набора запросов в сериализованный экземпляр класса объект будет использоваться как.instance
поставка. Если начальный объект не передан, то.instance
имущество будетNone
.
При передаче данных в сериализованный экземпляр класса неизмененные данные будут.initial_data
поставка. Если аргумент ключевого слова данных не передается, то.initial_data
собственности не будет.
Частичное обновление
По умолчанию сериализатор должен передавать значения для всех обязательных полей, иначе будет выброшена ошибка проверки. ты можешь использовать этоpartial
параметр, разрешающий частичные обновления.
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
Работа с вложенными объектами
Предыдущие примеры подходят для работы с объектами только с простыми типами данных, но иногда вам также необходимо иметь возможность представлять более сложные объекты, где некоторые свойства объекта могут не быть простыми типами данных, такими как строки, даты или целые числа. .
Serializer
Сам класс представляет собойField
, который можно использовать для представления отношения, в котором один тип объекта вложен в другой тип объекта.
class UserSerializer(serializers.Serializer):
email = serializers.EmailField()
username = serializers.CharField(max_length=100)
class CommentSerializer(serializers.Serializer):
user = UserSerializer()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
Если вложенные объекты могут бытьNone
значение,required = False
Флаги для передачи во вложенные классы сериализации.
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False) # May be an anonymous user.
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
Аналогично, если вложенный объект является списком, он должен бытьmany = True
Флаги для передачи во вложенные классы сериализации.
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False)
edits = EditItemSerializer(many=True) # A nested list of 'edit' items.
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
Вложенное представление с возможностью записи
При работе с вложенными представлениями, которые поддерживают десериализованные данные, любые ошибки во вложенном объекте будут вложены под именем поля вложенного объекта.
serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'user': {'email': [u'Enter a valid e-mail address.']}, 'created': [u'This field is required.']}
такой же,.validated_data
Свойства будут содержать вложенные структуры данных.
писать для вложенного представления.create()
метод
Если вы поддерживаете вложенные представления с возможностью записи, вам нужно будет написать обработчик, который обрабатывает сохранение нескольких объектов..create()
или.update()
метод.
В следующем примере показано, как обрабатывать создание пользователей с вложенными объектами профилей.
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ('username', 'email', 'profile')
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user
писать для вложенного представления.update()
метод
Для обновлений необходимо тщательно продумать, как обрабатывать реляционные обновления. Например, если данные для отношенияNone
или не предусмотрено, что из следующего должно произойти?
- В базе данных установить отношение как
NULL
. - Удалить связанный экземпляр.
- Не обращайте внимания на данные и оставьте как есть.
- Выдает ошибку проверки.
Ниже приведен наш предыдущийUserSerializer
в классе.update()
Примеры методов.
def update(self, instance, validated_data):
profile_data = validated_data.pop('profile')
# Unless the application properly enforces that this field is
# always set, the follow could raise a `DoesNotExist`, which
# would need to be handled.
profile = instance.profile
instance.username = validated_data.get('username', instance.username)
instance.email = validated_data.get('email', instance.email)
instance.save()
profile.is_premium_member = profile_data.get(
'is_premium_member',
profile.is_premium_member
)
profile.has_support_contract = profile_data.get(
'has_support_contract',
profile.has_support_contract
)
profile.save()
return instance
Поскольку поведение вложенных операций создания и обновления может быть неоднозначным и может потребовать сложных зависимостей между связанными моделями, платформа REST 3 требует, чтобы вы всегда писали эти методы явно. дефолтModelSerializer
из.create()
и.update()
Метод не включает поддержку вложенных представлений с возможностью записи.
Однако доступны сторонние пакеты, например, поддерживающие автоматические вложенные представления с возможностью записи.DRF Writable Nested.
Сохраните соответствующий экземпляр в классе менеджера модели.
Другой способ сохранить несколько связанных экземпляров в сериализованном классе — написать собственный класс диспетчера моделей.
Например, предположим, что мы хотим убедиться, чтоUser
экземпляр иProfile
Экземпляры всегда создаются как пара. Мы могли бы написать собственный класс менеджера, как показано ниже:
class UserManager(models.Manager):
...
def create(self, username, email, is_premium_member=False, has_support_contract=False):
user = User(username=username, email=email)
user.save()
profile = Profile(
user=user,
is_premium_member=is_premium_member,
has_support_contract=has_support_contract
)
profile.save()
return user
Этот класс менеджера теперь лучше инкапсулирует то, что экземпляр пользователя и экземпляр профиля всегда создаются одновременно. Теперь можно переписать класс сериализации.create()
чтобы использовать новый метод класса управления.
def create(self, validated_data):
return User.objects.create(
username=validated_data['username'],
email=validated_data['email']
is_premium_member=validated_data['profile']['is_premium_member']
has_support_contract=validated_data['profile']['has_support_contract']
)
Работа с несколькими объектами
Serializer
Классы также могут выполнять сериализацию или десериализацию списков объектов.
Сериализация нескольких объектов
Чтобы сериализовать набор запросов или список объектов вместо одного экземпляра объекта, при создании экземпляра сериализованного класса вы должны передатьmany=True
логотип. Затем вы можете передать набор запросов или список объектов для сериализации.
queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
# [
# {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},
# {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},
# {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
# ]
Десериализовать несколько объектов
Поведение по умолчанию при десериализации нескольких объектов заключается в поддержке создания нескольких объектов, но не нескольких обновлений объектов.
Включить дополнительный контекст
В дополнение к сериализуемому объекту бывают случаи, когда для сериализованного класса требуется дополнительный контекст. Распространенным случаем является то, что если вы используете класс сериализации, который содержит отношение гиперссылки, вам нужен класс сериализации для доступа к текущему запросу, чтобы он мог правильно сгенерировать полный URL-адрес.
При создании экземпляра сериализованного объекта вы можете предоставить любой дополнительный контекст, передав параметр контекста. Например:
serializer = AccountSerializer(account, context={'request': request})
serializer.data
# {'id': 6, 'owner': u'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}
посетивself.context
свойств, контекстные словари можно использовать в любой логике сериализованного поля объекта, например в пользовательском.to_representation()
метод.
ModelSerializer
Часто вам нужно, чтобы классы сериализации были тесно связаны с определениями модели Django.
ModelSerializer
Класс предоставляет ярлык, позволяющий автоматически создаватьSerializer
Класс с полями, соответствующими полям класса модели.
ModelSerializer
класс и рутинаSerializer
Классы те же, за исключением того, что:
- Он автоматически генерирует набор полей на основе модели.
- Он автоматически генерирует валидаторы для сериализованных классов, такие как валидатор unique_together.
- это содержит
.create()
и.update()
Простая реализация по умолчанию .
Объявите ModelSerializer следующим образом:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('id', 'account_name', 'users', 'created')
По умолчанию все поля класса модели в этом классе будут сопоставлены с соответствующими полями сериализованного класса.
Любые отношения (например, внешний ключ в модели) будут сопоставлены сPrimaryKeyRelatedField
. Обратные связи не включаются по умолчанию, если они не указаны в документации по отношениям сериализации.
экзаменModelSerializer
Класс сериализатора может генерировать строку представления, позволяющую полностью проверить состояние его полей. в настоящее время используетModelSerializer
Это особенно полезно при работе, когда вам нужно определить, какие поля и валидаторы он автоматически создает для вас.
Для этого используйтеpython manage.py shell
Перейдите в оболочку Django, затем импортируйте класс сериализации, создайте его экземпляр и распечатайте представление объекта...
>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))
AccountSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(allow_blank=True, max_length=100, required=False)
owner = PrimaryKeyRelatedField(queryset=User.objects.all())
Укажите поля для включения
Если вы хотите использовать только подмножество полей по умолчанию в сериализаторе модели, вы можете использоватьfields
илиexclude
вариант для этого, как и при использованииModelForm
Такой же. Настоятельно рекомендуется явно использоватьfields
Все поля для сериализации свойств. Это снизит вероятность непреднамеренного раскрытия данных при изменении модели.
Возьмите каштан:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('id', 'account_name', 'users', 'created')
Вы также можете поставитьfields
свойству присвоено особое значение'__all__'
, чтобы указать, что все поля в модели должны использоваться.
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = '__all__'
ты можешь поставитьexclude
Для свойства задан список полей, которые необходимо исключить из сериализатора.
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
exclude = ('users',)
В приведенном выше примере, еслиAccount
Модель имеет 3 поляaccount_name
,users
иcreated
, появится полеaccount_name
иcreated
сериализуется.
fields
иexclude
Имена в свойствах обычно сопоставляются с полями модели класса модели.
илиfields
Имена в параметрах могут быть сопоставлены со свойствами или методами. не становясь параметром в классе модели.
Начиная с версии 3.3.0, одно из этих свойств должно быть предоставленоfields
илиexclude
.
указать вложенную сериализацию
дефолтModelSerializer
Используйте первичные ключи для ассоциации, но вы также можете использоватьdepth
Возможность легко генерировать вложенные представления (самоассоциация):
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('id', 'account_name', 'users', 'created')
depth = 1
depth
Параметры должны быть установлены на целочисленное значение, указывающее глубину ассоциации, которую необходимо пройти, прежде чем вернуться к плоскому представлению.
Если вы хотите настроить способ сериализации, вам нужно определить поля самостоятельно.
Явно указать поля
Вы можете добавить дополнительные поля вModelSerializer
или переопределите поле по умолчанию, объявив поле в классе, как вы сделали сSerializer
класс делает.
class AccountSerializer(serializers.ModelSerializer):
url = serializers.CharField(source='get_absolute_url', read_only=True)
groups = serializers.PrimaryKeyRelatedField(many=True)
class Meta:
model = Account
Дополнительные поля могут соответствовать любому свойству или вызываемому полю модели.
Укажите поля только для чтения
Вы можете назначить несколько полей только для чтения. Не добавляйте явно в каждое полеread_only = True
свойства, вы можете использовать мета-параметр ярлыкаread_only_fields
.
Параметр должен быть списком или кортежем имен полей, объявленных следующим образом:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('id', 'account_name', 'users', 'created')
read_only_fields = ('account_name',)
содержатьeditable = False
поля модели,AutoField
Поля доступны только для чтения по умолчанию и их не нужно добавлять вread_only_fields
опции.
Уведомление: существует особый случай, когда поля только для чтения находятся на уровне модели.
unique_together
часть ограничений. В этом случае класс сериализации требует проверки для ограничения поля, но пользователь также не может редактировать его.
Правильный способ справиться с этим — явно указать поля в классе сериализации, предоставив при этом
read_only = True
иdefault = ...
аргументы ключевых слов.
Примером этого является текущая сертификация.
User
отношения только для чтения с другим идентификатором, которыйunique_together
. В этом случае вы должны объявить пользовательское поле следующим образом:
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
Я расскажу о проверке позже
Дополнительные аргументы ключевого слова
Существует также ярлык, который позволяет использоватьextra_kwargs
Параметр указывает любые дополнительные аргументы ключевого слова в поле. иread_only_fields
Это означает, что вам не нужно явно объявлять поле в классе сериализатора.
Параметр представляет собой словарь, отображающий имена полей в словарь аргументов ключевых слов. Например:
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email', 'username', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User(
email=validated_data['email'],
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
реляционное поле
При сериализации экземпляра модели можно выбрать несколько различных способов представления отношений.ModelSerializer
По умолчанию используется первичный ключ связанного экземпляра.
Другие представления включают сериализацию с гиперссылками, сериализацию полностью вложенных представлений или сериализацию с пользовательскими представлениями.
настраиваемое сопоставление полей
Класс ModelSerializer также предоставляет API, который можно переопределить для изменения полей сериализованного объекта по мере его создания.
Обычно, еслиModelSerializer
Нет возможности сгенерировать поля, требуемые по умолчанию, тогда вы должны добавить их в класс явно, или использовать обычныйSerializer
своего рода. Однако в некоторых случаях может потребоваться создать новый базовый класс, определяющий, как создавать поля сериализованного объекта для данной модели.
.serializer_field_mapping
Сопоставление классов модели Django с классами сериализации фреймворка REST. Вы можете переопределить это сопоставление, чтобы изменить класс сериализации по умолчанию, который следует использовать для каждого класса модели.
.serializer_related_field
Это свойство должно быть классом поля сериализатора, который по умолчанию используется для реляционных полей.
заModelSerializer
, который по умолчанию равенPrimaryKeyRelatedField
.
заHyperlinkedModelSerializer
, который по умолчанию равенserializers.HyperlinkedRelatedField
.
serializer_url_field
Класс поля Serializer, который следует использовать для сериализации любогоurl
поле.
По умолчаниюserializers.HyperlinkedIdentityField
.
serializer_choice_field
Класс поля сериализатора, который следует использовать для любых полей выбора в сериализаторе.
По умолчаниюserializers.ChoiceField
.
API field_class и field_kwargs
Следующий метод вызывается для определения аргументов класса и ключевого слова для каждого поля, которое должно автоматически включаться в сериализатор. Все эти методы должны возвращать два кортежа(field_class, field_kwargs)
.
.build_standard_field(self, field_name, model_field)
Вызывается для создания полей сериализатора, которые сопоставляются с полями стандартной модели.
Реализация по умолчанию основана наserializer_field_mapping
Свойство возвращает сериализованный класс.
.build_relational_field(self, field_name, relation_info)
Вызывается для создания полей сериализатора, которые сопоставляются с полями реляционной модели.
Реализация по умолчанию основана наserializer_relational_field
Свойство возвращает сериализованный класс.
relation_info
Параметр представляет собой именованный кортеж, содержащийmodel_field
,related_model
,to_many
иhas_through_model
Атрибуты.
.build_nested_field(self, field_name, relation_info, nested_depth)
когдаdepth
Когда параметр установлен, вызывается для создания полей сериализатора, которые сопоставляются с полями реляционной модели.
Реализация по умолчанию динамически создаетModelSerializer
илиHyperlinkedModelSerializer
Вложенный класс сериализации.
nested_depth
будетdepth
Значение опции уменьшается на 1.
relation_info
Параметр представляет собой именованный кортеж, содержащийmodel_field
,related_model
,to_many
иhas_through_model
Атрибуты.
.build_property_field(self, field_name, model_class)
Вызывается для создания полей сериализатора, которые сопоставляются со свойствами или методами без аргументов в классе модели.
Реализация по умолчанию возвращаетReadOnlyField
своего рода.
.build_url_field(self, field_name, model_class)
вызывается для собственного сериализатораurl
Поле создает поле сериализатора.
Реализация по умолчанию возвращаетHyperlinkedIdentityField
своего рода.
.build_unknown_field(self, field_name, model_class)
Вызывается, когда имя поля не соответствует какому-либо полю или свойству модели. Реализация по умолчанию выдает ошибку. Но подклассы могут настроить это поведение.
HyperlinkedModelSerializer
HyperlinkedModelSerializer
класс сModelSerializer
Классы похожи, за исключением того, что они используют гиперссылки для представления отношений вместо первичных ключей.
По умолчанию сериализатор будет содержатьurl
поля вместо полей первичного ключа.
поле URL будет использоватьHyperlinkedIdentityField
Поле сериализатора для представления, и любые отношения в модели будут использоватьHyperlinkedRelatedField
Поле сериализатора для представления.
Вы можете сделать это, добавив первичный ключ вfields
возможность явного включения первичного ключа, например:
class AccountSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Account
fields = ('url', 'id', 'account_name', 'users', 'created')
Абсолютные и относительные URL-адреса
в инстанцированииHyperlinkedModelSerializer
, текущий запрос должен быть включен в контекст сериализации, например:
serializer = AccountSerializer(queryset, context={'request': request})
Это гарантирует, что гиперссылка может содержать соответствующее имя хоста для создания полного URL-адреса, например:
http://api.example.com/accounts/1/
вместо относительного URL, например:
/accounts/1/
Если вы действительно хотите использовать относительные URL-адреса, вы должны явно передать их в контексте сериализации.{'request':None}
.
Как определить вид гиперссылки
Необходимо определить, какие виды следует использовать для создания гиперссылок на экземпляры модели.
По умолчанию ожидается, что гиперссылки будут соответствовать стилям с'{model_name}-detail'
соответствующее имя представления и передатьpk
Экземпляр поиска аргумента ключевого слова.
ты можешь использовать этоextra_kwargs
в настройкахview_name
иlookup_field
Параметры переопределяют имя представления поля URL-адреса и поля подстановки следующим образом:
class AccountSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Account
fields = ('account_url', 'account_name', 'users', 'created')
extra_kwargs = {
'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},
'users': {'lookup_field': 'username'}
}
Кроме того, поля в сериализованном классе можно задать явно. Например:
class AccountSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='accounts',
lookup_field='slug'
)
users = serializers.HyperlinkedRelatedField(
view_name='user-detail',
lookup_field='username',
many=True,
read_only=True
)
class Meta:
model = Account
fields = ('url', 'account_name', 'users', 'created')
Совет: правильное сопоставление гиперссылок и URL-адресов иногда может быть немного сложным. Распечатать
HyperlinkedModelSerializer
примерrepr
это особенно полезный способ проверить, какие именно имена представлений и поля поиска должны отображаться в этих отношениях.
Изменить имя поля URL
Имя поля URL-адреса по умолчанию равно 'url'. можно использоватьURL_FIELD_NAME
(в файле настроек) Переопределить этот параметр глобально.
ListSerializer
ListSerializer
Класс обеспечивает поведение сериализации и одновременной проверки нескольких объектов. Обычно вам не нужно использовать напрямуюListSerializer
, вместо этого его следует просто передать при создании экземпляра сериализованного классаmany=True
.
Когда сериализованный класс создается иmany = True
проходит, аListSerializer
экземпляр будет создан. Сериализованный класс становится родительскимListSerializer
ребенок
Следующие параметры также могут быть переданы вListSerializer
поле или прошлоmany = True
Класс сериализации:
allow_empty
По умолчанию этоTrue
, но если вы хотите запретить пустые списки в качестве допустимых входных данных, вы можете установить для него значениеFalse
.
настроитьListSerializer
поведение
Есть несколько ситуаций, когда может потребоваться настройкаListSerializer
поведение. Например:
- Хотите обеспечить определенную проверку списков, например проверку того, что один элемент не конфликтует с другим элементом в списке.
- Хотите настроить поведение создания или обновления нескольких объектов.
В этих случаях это можно сделать с помощью класса сериализацииMeta
в классеlist_serializer_class
возможность изменить переданныйmany=True
класс для использования.
class CustomListSerializer(serializers.ListSerializer):
...
class CustomSerializer(serializers.Serializer):
...
class Meta:
list_serializer_class = CustomListSerializer
Настройка создания нескольких объектов
Реализация по умолчанию для создания нескольких объектов заключается в простом вызове каждого элемента в списке..create()
. Если вы хотите настроить это поведение, вам нужно передатьmany=True
обычайListSerializer
класс.create()
метод.
class BookListSerializer(serializers.ListSerializer):
def create(self, validated_data):
books = [Book(**item) for item in validated_data]
return Book.objects.bulk_create(books)
class BookSerializer(serializers.Serializer):
...
class Meta:
list_serializer_class = BookListSerializer
Настройка обновления нескольких объектов
по умолчанию,ListSerializer
Классы не поддерживают обновления нескольких объектов. Это связано с тем, что ожидаемое поведение операций вставки и удаления неоднозначно.
Для поддержки многообъектных обновлений необходимо переопределить метод обновления. При написании кода обновления для нескольких объектов обязательно помните о следующем:
- Как определить, какой экземпляр следует обновить для каждого элемента в списке данных?
- Как следует обращаться со вставками? Являются ли они недействительными или создают новые объекты?
- Как следует обрабатывать удаления? Подразумевают ли они удаление объекта или удаление отношения? Следует ли их игнорировать или они недействительны?
- Как справиться с сортировкой? Означает ли изменение положения двух элементов изменение состояния или оно игнорируется?
Вам нужно добавить явный класс сериализации экземпляраid
поле. Неявно сгенерированный по умолчаниюid
Поле отмечено какread_only
. Это приведет к его удалению при обновлении. Как только вы явно объявите его, он будет доступен в методе обновления класса сериализатора списка.
Вот пример того, как вы можете реализовать обновление нескольких объектов:
class BookListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
# Maps for id->instance and id->data item.
book_mapping = {book.id: book for book in instance}
data_mapping = {item['id']: item for item in validated_data}
# Perform creations and updates.
ret = []
for book_id, data in data_mapping.items():
book = book_mapping.get(book_id, None)
if book is None:
ret.append(self.child.create(data))
else:
ret.append(self.child.update(book, data))
# Perform deletions.
for book_id, book in book_mapping.items():
if book_id not in data_mapping:
book.delete()
return ret
class BookSerializer(serializers.Serializer):
# We need to identify elements in the list using their primary key,
# so use a writable field here, rather than the default which would be read-only.
id = serializers.IntegerField()
...
class Meta:
list_serializer_class = BookListSerializer
Пользовательская инициализация ListSerializer
когда естьmany=True
Когда создается экземпляр сериализованного класса, нам нужно определить, какие параметры и аргументы ключевых слов должны быть переданы дочерним элементам.Serializer
класс и родительListSerializer
Категория.__ init __()
метод.
Реализация по умолчанию заключается в передаче всех параметров обоим классам, кромеvalidators
и любые аргументы пользовательского ключевого слова, оба из которых, как предполагается, используются для классов субсериализации.
Иногда вам может понадобиться явно указать при передачеmany=True
Как создавать экземпляры подклассов и суперклассов. ты можешь использовать этоmany_init
метод класса для этого.
@classmethod
def many_init(cls, *args, **kwargs):
# Instantiate the child serializer.
kwargs['child'] = cls()
# Instantiate the parent list serializer.
return CustomListSerializer(*args, **kwargs)
BaseSerializer
BaseSerializer
Классы можно использовать для простой поддержки других стилей сериализации и десериализации.
Этот класс реализуетSerializer
Тот же базовый API, что и у класса:
-
.data
- Возвращает исходящее необработанное представление. -
.is_valid()
- Десериализовать и проверять входящие данные. -
.validated_data
- Возвращает проверенные входящие данные. -
.errors
- возвращает ошибку при проверке. -
.save()
- Сохраните проверенные данные в экземпляре объекта.
Существует четыре метода, которые можно переопределить, в зависимости от того, какую функциональность вы хотите, чтобы ваш класс сериализации поддерживал:
-
.to_representation()
- Переопределите эту операцию для поддержки сериализации для операций чтения. -
.to_internal_value()
- Переопределите эту операцию для поддержки десериализации операций записи. -
.create() 和 .update()
- Переопределить один или оба для поддержки сохранения экземпляров.
Поскольку этот класс предоставляетSerializer
класс с тем же интерфейсом, поэтому вы можете использовать существующий обычныйSerializer
илиModelSerializer
Например, используйте его с общими представлениями на основе классов.
Единственная разница в том,BaseSerializer
Класс не создает HTML-формы в доступном для просмотра API. Это связано с тем, что данные, которые они возвращают, не содержат всей информации о полях, которая позволила бы отображать каждое поле как соответствующий ввод HTML.
Read-only BaseSerializer
своего рода
нужно использоватьBaseSerializer
Класс реализует класс сериализации только для чтения, нам просто нужно переопределить.to_representation()
метод. Давайте рассмотрим пример с использованием простой модели Django:
class HighScore(models.Model):
created = models.DateTimeField(auto_now_add=True)
player_name = models.CharField(max_length=10)
score = models.IntegerField()
создан дляHighScore
Класс сериализации только для чтения, который преобразует экземпляры в примитивные типы данных, очень прост.
class HighScoreSerializer(serializers.BaseSerializer):
def to_representation(self, obj):
return {
'score': obj.score,
'player_name': obj.player_name
}
Теперь мы можем использовать этот класс для сериализации одногоHighScore
Пример:
@api_view(['GET'])
def high_score(request, pk):
instance = HighScore.objects.get(pk=pk)
serializer = HighScoreSerializer(instance)
return Response(serializer.data)
Или используйте его для сериализации нескольких экземпляров:
@api_view(['GET'])
def all_high_scores(request):
queryset = HighScore.objects.order_by('-score')
serializer = HighScoreSerializer(queryset, many=True)
return Response(serializer.data)
Чтение-запись класса BaseSerializer
Чтобы создать класс сериализации для чтения и записи, нам сначала нужно реализовать.to_internal_value()
метод. Этот метод возвращает проверочное значение, которое будет использоваться для создания экземпляра объекта, и может повышаться, если предоставленные данные имеют неправильный формат.ValidationError
.
После реализации.to_internal_value()
, базовый API проверки будет доступен в сериализаторе, и вы сможете использовать.is_valid()
,.validated_data
и.errors
.
Если вы все еще хотите поддержать.save()
, также необходимо реализовать.create()
и.update()
один или оба метода.
Ниже приведен наш предыдущийHighScoreSerializer
Полный пример , который был обновлен для поддержки операций чтения и записи.
class HighScoreSerializer(serializers.BaseSerializer):
def to_internal_value(self, data):
score = data.get('score')
player_name = data.get('player_name')
# Perform the data validation.
if not score:
raise ValidationError({
'score': 'This field is required.'
})
if not player_name:
raise ValidationError({
'player_name': 'This field is required.'
})
if len(player_name) > 10:
raise ValidationError({
'player_name': 'May not be more than 10 characters.'
})
# Return the validated values. This will be available as
# the `.validated_data` property.
return {
'score': int(score),
'player_name': player_name
}
def to_representation(self, obj):
return {
'score': obj.score,
'player_name': obj.player_name
}
def create(self, validated_data):
return HighScore.objects.create(**validated_data)
Создать новый базовый класс
Если вы хотите реализовать новый общий класс сериализации для обработки определенного стиля сериализации или для интеграции с необязательным сервером хранения, тогдаBaseSerializer
Также полезны занятия.
Следующие классы являются примерами универсальных классов сериализации, которые могут обрабатывать приведение произвольных объектов к их базовому представлению.
class ObjectSerializer(serializers.BaseSerializer):
"""
A read-only serializer that coerces arbitrary complex objects
into primitive representations.
"""
def to_representation(self, obj):
for attribute_name in dir(obj):
attribute = getattr(obj, attribute_name)
if attribute_name('_'):
# Ignore private attributes.
pass
elif hasattr(attribute, '__call__'):
# Ignore methods and other callables.
pass
elif isinstance(attribute, (str, int, bool, float, type(None))):
# Primitive types can be passed through unmodified.
output[attribute_name] = attribute
elif isinstance(attribute, list):
# Recursively deal with items in lists.
output[attribute_name] = [
self.to_representation(item) for item in attribute
]
elif isinstance(attribute, dict):
# Recursively deal with items in dictionaries.
output[attribute_name] = {
str(key): self.to_representation(value)
for key, value in attribute.items()
}
else:
# Force anything else to its string representation.
output[attribute_name] = str(attribute)
Сериализатор использует расширенный
Переопределить поведение сериализации и десериализации
Если вам нужно изменить поведение сериализации или десериализации сериализованного класса, вы можете переопределить.to_representation()
или.to_internal_value()
метод достижения.
Эти два метода, возможно, придется переопределить по следующим причинам...
- Добавьте новое поведение для нового базового класса сериализации.
- Немного изменить поведение существующих классов.
- Повысьте производительность сериализации для часто используемых конечных точек API, которые возвращают большие объемы данных.
Сигнатуры этих методов следующие:
.to_representation(self, obj)
Принимает экземпляр объекта, который необходимо сериализовать, и возвращает необработанное представление. Обычно это означает возврат структуры встроенных типов данных Python. Точные типы, которые можно обрабатывать, зависят от класса рендеринга, который вы настроили для API.
Может быть переопределен для изменения стиля презентации. Например:
def to_representation(self, instance):
"""Convert `username` to lowercase."""
ret = super().to_representation(instance)
ret['username'] = ret['username'].lower()
return ret
.to_internal_value(self, data)
Принимает непроверенные входящие данные в качестве входных данных и должен возвращать какserializer.validated_data
Предоставлены данные проверки. Если вызывается в сериализованном классе.save()
, возвращаемое значение также будет передано в.create()
или.update()
метод.
Если проверка не пройдена, метод выдаетserializers.ValidationError(errors)
.errors
Параметр должен быть полем, названным по имени поля (илиsettings.NON_FIELD_ERRORS_KEY
) сопоставление со словарем списков сообщений об ошибках. Если вам не нужно изменять поведение десериализации, но вы хотите обеспечить проверку на уровне объекта, вместо этого рекомендуется переопределить.validate()
метод.
перешли на этот методdata
Параметры обычноrequest.data
, поэтому тип предоставляемых данных будет зависеть от класса синтаксического анализатора, который вы настроили для API.
Наследовать класс сериализации
Подобно формам Django, вы можете расширять и повторно использовать классы сериализации посредством наследования. Это позволяет объявить общий набор полей или методов в родительском классе, который затем можно использовать в нескольких классах сериализации. Например,
class MyBaseSerializer(Serializer):
my_field = serializers.CharField()
def validate_my_field(self):
...
class MySerializer(MyBaseSerializer):
...
с ДжангоModel
иModelForm
Как и классы, сериализуйте внутренний класс в классеMeta
Класс не начинается внутри своего родительского классаMeta
Неявное наследование в классах. если ты хочешьMeta
Класс наследует родительский класс и должен быть четко указан. Например:
class AccountSerializer(MyBaseSerializer):
class Meta(MyBaseSerializer.Meta):
model = Account
Обычно мы рекомендуем против внутреннегоMeta
В классе используется наследование, вместо этого явно объявляются все опции.
Динамически изменять поля
После инициализации класса сериализации вы можете использовать.fields
Свойство обращается к набору словарей полей в классе сериализации. Получая доступ к этому свойству и изменяя его, можно достичь цели динамического изменения класса сериализации.
Изменить напрямуюfields
Параметры позволяют делать интересные вещи, например изменять параметры сериализованных полей во время выполнения, а не при объявлении сериализованного класса.
Возьмите каштан:
Например, если вы хотите установить, какие поля должен использовать сериализованный класс при инициализации, вы можете создать такой сериализованный класс следующим образом:
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
Это позволит вам сделать следующее:
>>> class UserSerializer(DynamicFieldsModelSerializer):
>>> class Meta:
>>> model = User
>>> fields = ('id', 'username', 'email')
>>>
>>> print UserSerializer(user)
{'id': 2, 'username': 'jonwatts', 'email': 'jon@example.com'}
>>>
>>> print UserSerializer(user, fields=('id', 'email'))
{'id': 2, 'email': 'jon@example.com'}