Home > Mobile >  How to show a field seperately in drf
How to show a field seperately in drf

Time:11-30

I have Reviews & Ratings serializer. I want to show the total count of reviews in response. The current implementation I am getting review count but it shows on all review response like below:

[
    {
        "review_count": 2,
        "user": "don sebastian",
        "rating": 3.9,
        "review": "Rating for pendant 1 by Don",
        "created_at": "2022-11-27",
        "updated_at": "2022-11-27"
    },
    {
        "review_count": 2,
        "user": "Jackson Patrick Gomez",
        "rating": 4.5,
        "review": "cool review Pendant 1",
        "created_at": "2022-11-27",
        "updated_at": "2022-11-29"
    }
]

What I want to get is like this review_count seperatley

[
   "review_count": 2,
    {
        "user": "don sebastian",
        "rating": 3.9,
        "review": "Rating for pendant 1 by Don",
        "created_at": "2022-11-27",
        "updated_at": "2022-11-27"
    },
    {
        "user": "Jackson Patrick Gomez",
        "rating": 4.5,
        "review": "cool review Pendant 1",
        "created_at": "2022-11-27",
        "updated_at": "2022-11-29"
    }
]

#Serializer.py

class ReviewSerializer(ModelSerializer):
    user = SerializerMethodField()
    review_count = SerializerMethodField()

    class Meta:
        model = ReviewRatings
        fields = ["review_count", "user", "rating", "review", "created_at", "updated_at"]

    def get_user(self, obj):
        return f"{obj.user.first_name} {obj.user.last_name}"
    
    def get_review_count(self, obj):

#Views.py

class ShowReviews(APIView):
    def get(self, request, *args, **kwargs):
        product_slug = self.kwargs['product_slug']
        rating = request.GET.get('rating')
        reviews = ReviewRatings.objects.filter(product__slug=product_slug)
        review_count = reviews.count()
        if rating == 'lowest':
            reviews = reviews.order_by('rating')
        elif rating == 'highest':
            reviews = reviews.order_by('-rating')
        if not reviews:
            return Response({"error": "No reviews for this product yet"}, status=404)
        serializer = ReviewSerializer(reviews, many=True, context={"count":review_count})
        return Response(serializer.data, status=status.HTTP_200_OK)


#Edited Views.py


class ShowReviews(APIView):
    def get(self, request, *args, **kwargs):
        product_slug = self.kwargs['product_slug']
        rating = request.GET.get('rating')
        reviews = ReviewRatings.objects.filter(product__slug=product_slug)
        review_count = reviews.count()
        if rating == 'lowest':
            reviews = reviews.order_by('rating')
        elif rating == 'highest':
            reviews = reviews.order_by('-rating')
        if not reviews:
            return Response({"error": "No reviews for this product yet"}, status=404)
        serializer = ReviewSerializer(reviews, many=True)
        dict_copy = serializer.data.copy()
        dict_copy[0]={"review_count": review_count}
        return Response(dict_copy, status=status.HTTP_200_OK)

CodePudding user response:

The easiest way I would assume is to edit your endpoint response directly.

Assuming you approached DRF as instructed; (this is an easy guideline for you to set up), you are going to remove review_count from your serializer and approach your get method like so:

def get(self, request, *args, **kwargs):
      ..........
      serializer = ReviewSerializer(reviews, many=True)
      dict_copy = serializer.data.copy()
      dict_copy[0]=str(Review.objects.all().count()) # or wherever that count comes from
      return Response(dict_copy, status=status.HTTP_200_OK)

This way you are making a copy of the serializer and then appending your value there. Since serializer.data returns an array with a dict inside in order to access that point then you will do dict_copy[0]. Otherwise if you want to have access to it as a key-value pair you can assign it as

      dict_copy[0]={"review_count": str(Review.objects.all().count())}

and your result will be something like this:

[
    {
        "review_count": "4"
    },
    {
        "user": "don sebastian",
        "rating": 3.9,
        "review": "Rating for pendant 1 by Don",
        "created_at": "2022-11-27",
        "updated_at": "2022-11-27"
    },

Lastly you can try directly editing your response and adding there a key-pair value but I assume it will do you no good as this is outside of your serializer:

  x = Review.objects.all().count()
  return Response(( {"review_count":str(x)}, serializer.data), status=status.HTTP_200_OK)
[
    {
        "review_count": "4"
    },
    [
    {
       
        "user": "don sebastian",
        "rating": 3.9,
        "review": "Rating for pendant 1 by Don",
        "created_at": "2022-11-27",
        "updated_at": "2022-11-27"
    },
        ....
]
  • Related