Невозможно распаковать неитерабельный объект SerializerMethodField в Django DRF

Я пытаюсь присвоить список из SerializerMethodField() return набору из двух полей, как:

class PostSerializer(serializers.ModelSerializer):
    postvotes, postvote = serializers.SerializerMethodField()
    
    def get_postvotes(self, obj):
        qset = PostVote.objects.filter(Q(post=obj))
        votes = [PostVoteSerializer(m).data for m in qset]
        vote = sum(vote['vote'] for vote in votes)
        return [votes, vote] # votes[], vote: Integer

Однако это не удается с ошибкой, упомянутой в заголовке.

Как я могу решить эту проблему? Спасибо.

Ошибка происходит потому, что SerializerMethodField не является итерабельным. Вы не вызываете get_postvotes() напрямую, чтобы получить список, который он возвращает.

Чтобы решить текущую проблему, просто объявите поле как обычно:

postvotes = serializers.SerializerMethodField()

Затем, когда вы обращаетесь к значению поля postvotes обычным способом, вы получите список из двух элементов:

votes, vote = obj.postvotes

Это изменение исправит непосредственную ошибку, но я не уверен, что оно будет работать так, как вы задумали. Поэтому вот несколько альтернативных решений:

  1. Вместо этого используйте составное поле, например ListField или DictField

    .
  2. Создайте пользовательское поле, расширив serializers.Field. Подробности см. в документации .

Другая возможность заключается в объявлении двух SerializerMethodFields:

votes = serializers.SerializerMethodField()
vote_count = serializers.SerializerMethodField()

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

    def count_votes(self, obj):
        qset = PostVote.objects.filter(Q(post=obj))
        self._votes = [PostVoteSerializer(m).data for m in qset]
        self._vote_count = sum(vote['vote'] for vote in votes)

Тогда вы можете просто вызвать этот метод из соответствующих методов:

    def get_votes(self, obj):
        if self._votes is None:
            self.count_votes()
        return self._votes

Аналогично для get_vote_count(). И не забудьте инициализировать переменные-члены:

    def __init__(self, *args, **kwargs):
        self.super(*args, **kwargs)
        self._votes = None
        self._vote_count = None
Вернуться на верх