Как сгладить список списков объектов в сериализаторах django-rest-framework? - PullRequest
0 голосов
/ 26 марта 2019

У меня есть 3 модели django, объединенные ForeignKey:

# models.py
class Album(models.Model):
    some_fields

class Track(models.Model):
    some_fields
    album = models.ForeignKey(
        Album,
        related_name='tracks',
        on_delete=models.CASCADE,
    )

class Comment(models.Model):
    some_fields
    track = models.ForeignKey(
        Track,
        related_name='comments',
        on_delete=models.CASCADE,
    )

Я хотел бы сериализовать модель альбома, чтобы просмотреть все комментарии всех ее треков. Я создал файл сериализатора следующим образом:

# serializers.py
class TrackSerializer(serializers.ModelSerializer):

    class Meta:
        model = Album
        fields = (some_fields, 'comments')

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = (some_fields, 'tracks')

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

# Output albums
[{
    "some_fields": some_values,
    "tracks": [{ "some_fields": some_values, "comments": [ comment1, comment2 ]},
            { "some_fields": some_values, "comments": []},
            { "some_fields": some_values, "comments": [ comment3 ]},]
},
{
    "some_fields": some_values,
    "tracks": [{ "some_fields": some_values, "comments": [ comment4, comment5 ]},
            { "some_fields": some_values, "comments": []},
            { "some_fields": some_values, "comments": [ comment6 ]},]
}]

# Desired output albums
[{
    "some_fields": some_values,
    "tracks": [{ "some_fields": some_values},
            { "some_fields": some_values},
            { "some_fields": some_values},],
    "comments": [ comment1, comment2, comment3]
},
{
    "some_fields": some_values,
    "tracks": [{ "some_fields": some_values},
            { "some_fields": some_values},
            { "some_fields": some_values},],
    "comments": [ comment4, comment5, comment6]
}]

Я попытался сгладить список непосредственно в файле сериализаторов, но я получил сообщение «TypeError: объект ListSerializer 'не повторяется».

# serializers.py
class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)
    comments = [comment for track in tracks for comment in track.comments]

    class Meta:
        model = Album
        fields = (some_fields, 'tracks', 'comments')

Есть ли какой-нибудь изящный способ как вывести плоский список напрямую с помощью сериализаторов? Или я должен сделать это позже в views.py? Теперь это выглядит просто так:

# views.py
class AlbumMixin(object):
    model = Album
    raise_exception = True
    serializer_class = AlbumSerializer

    def get_queryset(self):
        return Album.objects.all()

class AlbumList(AlbumMixin, generics.ListCreateAPIView):
    pass

Ответы [ 2 ]

2 голосов
/ 26 марта 2019

Вы можете добавить serializers.SerializerMethodField на AlbumSerializer и вернуть необходимые комментарии.

Примерно так:

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = "__all__"


class AlbumSerializer(serializers.ModelSerializer):
    comments = serializers.SerializerMethodField()
    tracks = TrackSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = (some_fields, "comments", "tracks")

    def get_comments(self, obj):
        comments = Comment.objects.filter(track__in=obj.tracks.all())
        return CommentSerializer(comments, many=True).data
        # or you can get rid of CommentSerializer
        # return comments.values("some_field")

См. SerializerMethodField документы здесь

Обновление

Вы можете улучшить запрос, используя один из @ c6754

comments = Comment.objects.filter(track__album_id=obj.id)
0 голосов
/ 26 марта 2019

Вы можете попробовать использовать serializerMethodField

# serializers.py
class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)
    comments = serializers.SerializerMethodField()

    class Meta:
        model = Album
        fields = (some_fields, 'tracks', 'comments')

    def get_comments(self, obj):
        comments = Comments.objects.filter(track__album_id=obj.pk)
        return CommentSerializer(comments, many=True).data
...