@Sazoks

Как сделать правильную сериализацию моделей?

Задача
Имеется контроллер-класс, обеспечивающий пагинацию по галереи через ajax.
Получая нужную выборку записей из модели, я преобразую ее в json-формат с помощью django.core.serializers.serialize, получая тем самым json-представления списка с объектами.
Далее это дело я отправляю на клиент с помощью JsonResponse.

Проблема
Но вот незадача, из-за того, что django.core.serializers.serialize работает с коллекцией объектов, я получаю СТРОКУ, а не список с сериализованными объектами. Из-за того, что это строка, JsonResponse еще раз конвертирует переданную ему СТРОКУ в json-формат. Из-за этого приходится 2 раза парсить json на клиенте, что как-то криво.
Для большей ясности приведу пример:
...
# Получаем список объектов.
image_list = paginator.get_page(num_page).object_list
# image_list - это List[GalleryImage], а json_image_list - это str.
# Это строка вида '[{...}, {...}, ...]', но это строка! Если я захочу получить первый
# элемент, я получу не его, а '['.
json_image_list = serializers.serialize(image_list)
# Отправляем ответ в json-формате. Из-за этого и без того строка json_image_list
# еще раз конвертирует в json-формат...
return JsonResponse(data=json_image_list, safe=False)

$.ajax({
    ...
    success: function(json_image_list) {
        // Я думал, что тут я получу список с конвертированными в json экземплярами модели.
        image_list = JSON.parse(json_image_list);
        // Но вместо этого я получаю СТРОКУ вида "[{...}, {...}, ...]", и мне, выходит, нужно еще раз писать JSON.parse().
    }
});

Вот в этом и проблема. Это криво. Чтобы этого избежать, нужно передать в JsonResponse не строку, а list() с конвертированными в json экземплярами модели.

Что я пробовал для решения задачи
  1. Использование модуля json
    Первое, что я пробовал, после сериализации коллекции с объектами десериализовать сам объект списка с объектами обратно в python-объект с помощью методы json.loads. Опять же, выглядит очень костыльно.

  2. Написание метода to_json в модели
    Затем я решил просто написать метод ручной сериализации экземпляра модели в json-формат, написав соответствующий метод. Был примерно такой код:
    image_list = []
    for image in paginator.get_page(num_page).object_list:
        image_list.append(image.to_json())

    Но и этот вариант кажется мне не гибким и каким-то велосипедным: зачем писать в такой простейшей задачи функционал, который и так есть, но который я просто не разобрался, как правильно использовать.

  3. Использование прекраснейших сериализаторов из DRF
    Наконец, самый приятный способ в использовании, но не самый приятный в осознании того, что ради обычной сериализации я установил целый отдельный фреймворк. Написание своего слоя сериализаторов на основе rest_framework.serializers.ModelSerializer. Теперь у меня есть целый отдельный настраиваемый слой сериализации без изменения самой модели и лишних телодвижений.
    # serializers.py
    from rest_framework import serializers
    from .models import GalleryImage
    
    class GalleryImageSerializer(serializers.ModelSerializer):
        """Сериализатор модели изобрежения в JSON"""
    
        image = serializers.SerializerMethodField()
    
        class Meta:
            model = GalleryImage
            fields = '__all__'
    
        @staticmethod
        def get_image(obj):
            return obj.image.url

    # views.py
    ...
    # Отправляем запрашиваемые по номеру страницы изображения из пагинатора.
    image_set = paginator.get_page(num_page).object_list
    json_image_set = [GalleryImageSerializer(image).data for image in image_set]
    ...

    Но опять же, устанавливать целый отдельный фреймворк, писать свой слой для сериализации в обычном шаблонном проекте Django... Как-то это все не так...



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

Спасибо!
  • Вопрос задан
  • 129 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы