Reputation: 437
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
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 aForeignKey
field, since Django will automatically add a "twin" field with an_id
suffix. Therefore it should bepet
, instead of.petId
Upvotes: 4