Reputation: 61
after looking through the docs for a while I haven't found a really good way to aggregate counts on a model within a serializer.
An example of this could be the standard up/down voting done on many sites.
class PostSerializer(serializers.Serializer):
pk = serializers.IntegerField(read_only=True)
up_vote = serializers.SerializerMethodField('cast_up_vote', write_only=True)
down_vote = serializers.SerializerMethodField('cast_down_vote', write_only=True)
votes = serializers.SerializerMethodField()
with models:
class Post(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
up_votes = models.IntegerField(default=0)
down_votes = models.IntegerField(default=0)
lets say we wanted to perform an update on a post with up_vote set. You'd want to increment up_votes by one. What's the proper way to go about that? I'm currently experimenting with SerializerMethodFields but I'm not having much luck with using the data attributes from the passed in data. I'm also thinking that the serializerMethodField might be the wrong way to go about this since it seems more useful in going from model to representation.
Feel free to comment if more information is needed, I'm about to investigate custom fields if that's the answer.
Upvotes: 1
Views: 1060
Reputation: 3496
You use SerializerMethodField but you didn't write any method for it. If you use SerializerMethodField, you have to write a method pointed by SerializerMethodField inside serializer. You can reach to the objects being serialized by 'obj' in that method.
Example:
class PostSerializer(serializers.Serializer):
pk = serializers.IntegerField(read_only=True)
up_vote = serializers.SerializerMethodField('cast_up_vote', write_only=True)
down_vote = serializers.SerializerMethodField('cast_down_vote', write_only=True)
votes = serializers.SerializerMethodField()
def cast_up_vote(self, obj):
obj.up_vote += 1
obj.save()
Please give the error traceback so that we could help better.
Upvotes: 1
Reputation: 766
You may use class attribute to perform such requirement. And simply write a function with name get_<field_name>
as following, and the framework will link them up.
from rest_framework import serializers
class IncrSrlz( serializers.Serializer ):
_incr = 0
count = serializers.SerializerMethodField()
def get_count( self, obj ):
self._incr += 1
return self._incr
Resulting:
>>> IncrSrlz( range(10,20), many=True ).data
[OrderedDict([('count', 1)]), OrderedDict([('count', 2)]), OrderedDict([('count', 3)]), OrderedDict([('count', 4)]), OrderedDict([('count', 5)]), OrderedDict([('count', 6)]), OrderedDict([('count', 7)]), OrderedDict([('count', 8)]), OrderedDict([('count', 9)]), OrderedDict([('count', 10)])]
Upvotes: 1