Naterz
Naterz

Reputation: 437

count the number of likes from another model Django

implementing a like model where user could like a pet. If user presses like, isLike would be true while unlike would be isLike is false Model

class pet(models.Model):
    name = models.CharField(max_length=50)

class likes(models.Model):
    petId = models.ForeignKey(
        "pet", on_delete=models.CASCADE, null=True)
    liker = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
    isLike = models.BooleanField(default=False)

class countlikes(models.Model):
    petId = models.ForeignKey(
        "pet", on_delete=models.CASCADE, null=True)
    numOfLikes = models.PositiveSmallIntegerField(default=0)


Serializer

class PetSerializer( serializers.ModelSerializer):
    class Meta:
        model = pet
        fields = '__all__'


class LikesSerializer( serializers.ModelSerializer):
    class Meta:
        model = likes
        fields = '__all__'


class CountlikesSerializer(DynamicFieldsMixin, serializers.ModelSerializer):

    class Meta:
        model = countlikes
        fields = '__all__'

Viewset

class PetViewSet(viewsets.ModelViewSet):
    queryset = pet.objects.all()
    permission_classes = [
        permissions.AllowAny
        # permissions.IsAuthenticated,
    ]
    serializer_class = PetSerializer

class LikesViewSet(viewsets.ModelViewSet):
    queryset = likes.objects.all()
    permission_classes = [
        permissions.AllowAny
        # permissions.IsAuthenticated,
    ]
    serializer_class = LikesSerializer

class CountlikesViewSet(viewsets.ModelViewSet):
    queryset = countlikes.objects.all()
    permission_classes = [
        permissions.AllowAny
        # permissions.IsAuthenticated,
    ]
    serializer_class = countlikesSerializer

what I tried: two get requests to get the Number of likes and if isLike is true or false. If user likes, i would increment the numOfLikes and decrement if user unlikes and then do a put request.

Upvotes: 2

Views: 1174

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476699

The countlikes will introduce data duplication in your modeling, and it turns out that keeping data in sync, is harder than it might look. Therefore I advice to remove the countlikes model. Especially since it is not a real entity: it is "pure fabrication".

You can add two extra fields in your PetSerializer:

class PetSerializer(serializers.ModelSerializer):
    likes = serializers.IntegerField()
    dislikes = serializers.IntegerField()

    class Meta:
        model = pet
        fields = ('id', 'name', 'likes', 'dislikes')

In your ModelViewSet, you then should pass a queryset that is annotated:

from django.db.models import Count, Sum, Value
from django.db.models.functions import Coalesce

class PetViewSet(viewsets.ModelViewSet):
    queryset = pet.objects.annotate(
        likes=Coalesce(Sum('likes__isLike'), Value(0)),
        dislikes=Coalesce(Count('likes')-Sum('likes__isLike'), Value(0))
    )
    serializer_class = PetSerializer

Note: normally a Django models, just like all classes in Python are given a name in PerlCase, not snake_case, so it should be: Pet instead of pet.

 

Note: normally a Django model is given a singular name, so Like instead of likes.

 

Note: Normally one does not add a suffix _id to a ForeignKey field, since Django will automatically add a "twin" field with an _id suffix. Therefore it should be pet, instead of petId.

Upvotes: 4

Related Questions