Django Rest Framework: порядок вложенных сериализаторов
Проблема с сортировкой вложенного сериализатора song_set
в Django REST Framework
Я столкнулся с проблемой сортировки вложенного сериализатора song_set
в своем проекте на Django. Мне нужно отсортировать элементы song_set
в формате JSON по полю timestamp
(или pk
) в обратном порядке, чтобы самые новые песни отображались первыми.
Вот пример JSON данных, с которыми я работаю:
{
"pk": 151,
"album_name": "Name",
"song_set": [
{
"pk": 3,
"timestamp": "5 seconds"
},
{
"pk": 2,
"timestamp": "10 seconds"
},
{
"pk": 1,
"timestamp": "15 seconds"
}
]
}
Модель
У меня есть следующие модели:
class Album(models.Model):
album_name = models.CharField(max_length=100, blank=True)
class Song(models.Model):
album = models.ForeignKey('album.Album', default=1, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
Сериализатор
И вот как выглядит мой сериализатор:
class SongListSerializer(HyperlinkedModelSerializer):
class Meta:
model = Song
fields = [
'pk',
'timestamp'
]
class AlbumSerializer(HyperlinkedModelSerializer):
song_set = SongListSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = [
'pk',
'album_name',
'song_set'
]
Вопрос: Как мне отсортировать song_set
по timestamp
или pk
в обратном порядке, чтобы на выходе получались самые новые песни в начале списка? Поделитесь, пожалуйста, рекомендациями по решению этой проблемы!
4 ответ(ов)
Вы можете использовать SerializerMethodField
и написать метод для этого.
class AlbumSerializer(HyperlinkedModelSerializer):
song_set = serializers.SerializerMethodField()
class Meta:
model = Album
fields = [
'pk',
'timestamp',
'song_set'
]
def get_song_set(self, instance):
songs = instance.song_set.all().order_by('-timestamp')
return SongListSerializer(songs, many=True).data
В приведённом коде мы создаем сериализатор для модели Album
, в котором поле song_set
определяется как SerializerMethodField
. Это позволяет вам создать специальный метод get_song_set
, который получает все песни, связанные с данным альбомом, сортирует их по времени создания в порядке убывания и возвращает сериализованные данные с помощью SongListSerializer
. Таким образом, вы можете легко включать связанный набор данных в ваш ответ.
Чтобы добавить метапараметр ordering в вашу модель Song, необходимо изменить класс Meta внутри модели. Например, вы можете установить порядок сортировки по полю timestamp
и идентификатору первичного ключа (pk
). Это можно сделать следующим образом:
class Song(models.Model):
album = models.ForeignKey('album.Album', default=1)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
class Meta:
ordering = ['timestamp', 'pk']
В этом примере песни будут по умолчанию сортироваться сначала по времени создания (timestamp
), а в случае одинакового времени — по их первичному ключу (pk
). Таким образом, вы сможете быстро получать песни в отсортированном порядке при выполнении запросов к базе данных.
В вашем ViewSet
вы можете указать queryset с помощью объекта Prefetch
, который можно фильтровать и сортировать по вашему усмотрению. Использование префетчинга позволяет выполнить всего один дополнительный запрос к базе данных (вместо одного запроса для каждого родительского объекта при использовании SerializerMethodField
), что значительно повышает производительность.
from rest_framework import viewsets
from django.db.models import Prefetch
class AlbumViewSet(viewsets.ModelViewSet):
queryset = Album.objects.prefetch_related(Prefetch('song_set',
queryset=Song.objects.order_by('-timestamp')))
Таким образом, вы улучшаете производительность вашего приложения, минимизируя количество запросов к базе данных.
Старый вопрос, но поскольку он все еще появляется в Google, хочу поделиться своим ответом. Попробуйте переопределить метод Serializer.to_representation
. Теперь вы можете делать практически все, включая настройку сортировки вашего ответа. В вашем случае это может выглядеть так:
class AlbumSerializer(HyperlinkedModelSerializer):
song_set = SongListSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = [
'pk',
'timestamp',
'song_set'
]
def to_representation(self, instance):
response = super().to_representation(instance)
response["song_set"] = sorted(response["song_set"], key=lambda x: x["timestamp"])
return response
Этот подход позволяет вам гибко настраивать форматированный выход для сериализованных данных.
Создание JSON-ответа с использованием Django и Python
"Не подлежит сериализации в формат JSON"
Django Rest Framework - Получение поля связанной модели в сериализаторе
Django REST Framework: Ошибка "Нет заголовка 'Access-Control-Allow-Origin'" в Chrome, работает в Firefox
Как отобразить все поля модели с помощью ModelSerializer?