null

Сериализация объектов через Django Serializers

Django serializers

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

from rest_framework import serializers
   
class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post # модель с которой мы работаем
        fields = ['id', 'title', 'content', 'author', 'created_at'] # необходимые нам поля модели

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

from rest_framework.renderers import JSONRenderer
from myapp.models import Post
from myapp.serializers import PostSerializer

# Получаем объект Post из базы данных (предположим, у нас есть запись в базе данных)
post = Post.objects.get(pk=1)

# Создаем экземпляр сериализатора и передаем объект Post для сериализации
serializer = PostSerializer(post)

# Сериализуем объект в JSON
json_data = JSONRenderer().render(serializer.data)

# Выводим сериализованные данные в виде JSON
print(json_data)

Пользовательские поля

При необходимости, можно добавлять в сериализатор кастомные поля. Например, это может быть полезно при необходимости привести данные поля к определенному формату или при агрегации данных. Для реализации этого можно использовать класс Field:

from rest_framework import serializers
   
class WordCountField(serializers.Field):
   def to_representation(self, obj):
       # Возвращает количество слов в тексте
       return len(obj.content.split())
   
   def to_internal_value(self, data):
       # В данном контексте мы не реализуем десериализацию
       return data

Также можно воспользоваться так называемым method field. В таком случае при сериализации эффект будет одинаковым:

from rest_framework import serializers
   
class EventSerializer(serializers.ModelSerializer):
   class Meta:
       model = Event
       fields = ['id', 'name', 'date']
       
   def get_is_upcoming(self, obj):
       return obj.date > timezone.now() # в итоге поле is_upcoming будет записано в сериализованный объект

Сериализация вложенных моделей

Для сериализации более сложных объектов, имеющих внешние связи, можно использовать вложенные сериализаторы. Пишется это несложно и выглядит так:

from rest_framework import serializers
   
class AuthorSerializer(serializers.ModelSerializer):
   class Meta:
       model = Author
       fields = ['id', 'name', 'birth_date']

class BookSerializer(serializers.ModelSerializer):
   author = AuthorSerializer()  # Вложенная сериализация

   class Meta:
       model = Book
       fields = ['id', 'title', 'publication_date', 'author']

Десериализация и валидация

Как было упомянуто в начале, пакет также предоставляет возможность десериализации данных в модель. При этом присутствует валидация, результат которой можно определить методом serializer.is_valid(). Например, таким будет базовый пример десериализации JSON-строки в объект с обработкой ошибок валидации:

from rest_framework.parsers import JSONParser
from myapp.models import Post
from myapp.serializers import PostSerializer
from django.utils.six import BytesIO

# Допустим, у нас есть JSON-строка объекта Post
json_data = '{"title": "Заголовок поста", "content": "Текст поста", "author": 1}'

# Десериализуем JSON данные в объект Post
data = JSONParser().parse(json_data)

# Создаем экземпляр сериализатора и передаем данные для десериализации
serializer = PostSerializer(data=data)

# Проверяем, что данные валидны и десериализуем их в объект Post
if serializer.is_valid():
    post_instance = serializer.save()
    print(f"Создан объект Post: {post_instance}")
else:
    print("Данные неверны и не могут быть десериализованы в объект Post.")

Итоги

Как можно заметить, это решение достаточно практично и расширяемо. В частности, оно позволяет проводить валидацию при десериализации, а также вводить пользовательские поля и управлять набором полей при сериализации. При этом дублирование кода сведено к минимуму, что тоже важно.

Вперед

Коротко о себе:

Текущая страница

Работаю Python разработчиком в Tune-it.

Занимаюсь проектами, связанными с платформой EDX.