0

Django Rest Framework: порядок вложенных сериализаторов

12

Проблема с сортировкой вложенного сериализатора 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 ответ(ов)

0

Вы можете использовать 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. Таким образом, вы можете легко включать связанный набор данных в ваш ответ.

0

Чтобы добавить метапараметр 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). Таким образом, вы сможете быстро получать песни в отсортированном порядке при выполнении запросов к базе данных.

0

В вашем 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')))

Таким образом, вы улучшаете производительность вашего приложения, минимизируя количество запросов к базе данных.

0

Старый вопрос, но поскольку он все еще появляется в 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

Этот подход позволяет вам гибко настраивать форматированный выход для сериализованных данных.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь