flaire flaire - 3 years ago 209
reST (reStructuredText) Question

Django Rest DRF : getting count of objects for reverse relation

Let's say I have two models.


class Item(models.Model):
name = models.CharField(max_length=32)
# other fields

class ItemRelation(models.Model):
item = models.ForeignKey(Item, related_name='relations_item')
user = models.ForeignKey(User, related_name='relations_user')
has_viewed = models.BooleanField(default=False)
has_loved = models.BooleanFields(default=False)

Now, what I want to do is I want to get the view_count and love_count for all items using django rest api.


class ItemView(ListAPIView):
queryset = Items.objects.all().prefetch_related(Prefetch('relations_item',
queryset=ItemRelation.objects.filter(Q(has_viewed=True) | Q(has_loved=True))
serializer_class = ItemSerializer

Well, this was the plan but I have absolutely no idea how to get the view_count and love_count for each item in the list-api-view. I tried quite a few things on my serializer but I don't think it's going to work.
I can however use SerializerMethod() to do the work, but that would go through the DB N+1 number of times. I have read through the docs along with a few other blogs for prefetch_related and I was able to do things easily until this count problem showed up.

Just a sample from my serializer.

class ItemSerializer(serializers.ModelSerializer):

class Meta:
model = Item
fields = ['name', 'relations_item']

Answer Source

I suppose you want to count the number of relations in which a) has_viewed==True and b) has_loved==True.

That should be possible by using annotate() with Django Conditional Expressions:

from django.db.models import Case, IntegerField, Sum, When

class ItemView(ListAPIView):
    queryset = Items.objects.annotate(
                       When(relations_item__has_viewed=True, then=1),
                       When(relations_item__has_loved=True, then=1),
    # ...
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download