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 serializerInfoSerializer
...
Вы передаете параметры сериализатору 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))
}