DRF + сериализатор для возврата пользовательских данных из нескольких моделей

В связи с этим вопросом я пытаюсь вернуть данные из нескольких моделей в одном запросе с помощью DRF.

class Artist(models.Model):
    artist_name = models.CharField(max_length=100)

class Genre(models.Model):
    genre_name = models.CharField(max_length=100)

class Album(models.Model):
    album_name = models.CharField(max_length=100)
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    genre = models.ForeignKey(Genre, on_delete=nodels.CASCADE)

Я хочу вернуть JSON-список всех вариантов альбомов и жанров для всех исполнителей.

Нечто вроде:

{
    "genres": ["techno", "rap", "rock", ...],
    "albums": ["nevermind", "collection", "fragile", ...]
}

Я создал пользовательский сериализатор:

class InfoSerializer(serializers.Serializer):
    albums = serializers.CharField()
    genres = serializers.CharField()

    class Meta:
        fields = ["albums", "genres"]

и набор представлений:

class ShelfStationOptionsViewSet(ViewSet):
    serializer_class = InfoSerializer

    def list(self, request):
        options = [{"albums": Album.objects.all()},
                   {"genres": Genre.objects.all()}]
        results = InfoSerializer(options, many = True)
        results.is_valid()
        return Response(results.data)

Сообщение об ошибке, которое я продолжаю получать:

KeyError when attempting to get value for field albums on serializer InfoSerializer ...

Вы передаете параметры сериализатору InfoSerializer, и этот сериализатор предполагает, что options имеет атрибут с названием альбомов и жанров. Поскольку у него его нет, он выдает ошибку. См. документацию drf

Дизайн вашего набора представлений выглядит так, как будто вы возвращаете несколько экземпляров, но на самом деле вы возвращаете один словарь, который имеет только два ключа. Альбомы и жанры независимы друг от друга, поэтому возвращать массив с many=True здесь не имеет никакого смысла.

Я бы предложил вам вернуть что-то подобное в APIView. Также вы можете получать album_name и genre_name только из базы данных, что сделает это немного более производительным.

{
    "albums": list(Album.objects.all().values_list('album_name', flat=True)),
                   
    "genres": list(Genre.objects.all().values_list('genre_name', flat=True))
}
Вернуться на верх