I'm trying to assign the list from SerializerMethodField()
return
to a set of two fields, as:
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
However, this fails with the title-metioned error.
How can I solve this? Thanks.
CodePudding user response:
The error happens because SerializerMethodField
isn't an iterable. You are not calling get_postvotes()
directly to get the list which it returns.
To fix the current problem, just declare the field as normal:
postvotes = serializers.SerializerMethodField()
Then when you access the value of the postvotes
field in the usual way, you will get the list of two items:
votes, vote = obj.postvotes
This change will fix the immediate error, but I'm unsure if it will work the way you intend. So here are some alternative solutions:
Use a composite field instead, such as
ListField
orDictField
Create a custom field by extending
serializers.Field
. See the docs for details.
Another possibility is to declare two SerializerMethodField
s:
votes = serializers.SerializerMethodField()
vote_count = serializers.SerializerMethodField()
Since these are attached to methods in your serializer class, you can do whatever you want. For example, you could have a helper method to count the votes:
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)
Then you can just call the method from the appropriate methods:
def get_votes(self, obj):
if self._votes is None:
self.count_votes()
return self._votes
Similarly for get_vote_count()
. And be sure to initialize member variables:
def __init__(self, *args, **kwargs):
self.super(*args, **kwargs)
self._votes = None
self._vote_count = None