Задача
Имеется контроллер-класс, обеспечивающий пагинацию по галереи через 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 экземплярами модели.
Что я пробовал для решения задачи
- Использование модуля json
Первое, что я пробовал, после сериализации коллекции с объектами десериализовать сам объект списка с объектами обратно в python-объект с помощью методы json.loads
. Опять же, выглядит очень костыльно.
- Написание метода to_json в модели
Затем я решил просто написать метод ручной сериализации экземпляра модели в json-формат, написав соответствующий метод. Был примерно такой код:
image_list = []
for image in paginator.get_page(num_page).object_list:
image_list.append(image.to_json())
Но и этот вариант кажется мне не гибким и каким-то велосипедным: зачем писать в такой простейшей задачи функционал, который и так есть, но который я просто не разобрался, как правильно использовать.
- Использование прекраснейших сериализаторов из 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... Как-то это все не так...
Вопрос
В общем, надеюсь, ясно описал проблему. Мне важно понять, как грамотно решать такую тривиальщину. Сам вопрос: какие существуют правильные способы решения такой тривиальной задачи, кроме описанных мной выше?
Спасибо!