1👍
Work with a serializer for the topic:
class TopicSerializer(serializers.ModelSerializer):
upvotes = serializers.IntegerField(read_only=True)
class Meta:
model = Topic
fields = ['id', 'name', 'upvotes']
then in the ModelViewSet
, you annotate:
from django.db.models import Sum
from rest_framework.viewsets import ModelViewSet
class TopicViewSet(ModelViewSet):
serializer_class = TopicSerializer
queryset = Topic.objects.annotate(upvotes=Sum('userupvotes__upvotes'))
0👍
Desired output
This is the result I want to get. When I don’t perform any aggregations (and there are views where this will be the case), it works.
[
{
"topic_name": 3,
"topic_name": "Korean Studies",
"upvotes": 14
},
{
"topic_name": 12,
"topic_name": "Inflation",
"upvotes": 3
},
]
The serialized FK will always give you the ID
of the related model. I am not sure why you name it topic_name
if that is equal to an ID
. Now, if you really want to get the name
field of the Topic
model
in the topic_name = serializers.StringRelatedField(source="topic")
you should give it a source="topic.name"
However, if you trying to get the ID of the relation you can still use ModelSerializer
:
class TopicUpvotesSerializer(serializers.ModelSerializer):
class Meta:
model = UserUpvotes
fields = "__all__"
0👍
@willem-van-onsem‘s answer is the correct one for the problem as I had put it.
But… I had another use case (sorry! ◑﹏◐), for when the Users API used UserUpvotes
serializer as a nested field. So I had to find another solution. This is was I eventually ended up with. I’m posting in case it helps anyone.
class UserUpvotesSerializer(serializers.ModelSerializer):
topic_name = serializers.SerializerMethodField()
def get_topic_name (self, obj):
try:
_topic_name = obj.topic.name
except TypeError:
_topic_name = obj.get("skill__name", None)
return _topic_name
class Meta:
model = UserUpvotes
fields = ["topic_id", "topic_name", "upvotes"]
I still have no idea why the SerializerMethodField
works and the StringRelatedField
field doesn’t. It feels like a bug?
Anyways, the rub here is that, after the values().annotate()
aggregation, obj
is no longer a QuerySet, but a dict. So accessing name
directly will give you a ‘UserUpvotes’ object is not subscriptable error.
I don’t know if there are any other edge cases I should be aware of (this is when I REALLY miss type hints in Django), but it works so far