Reputation: 3
I'am a newbie in Rest Framework in Django, and I have an exercise. I want to create custom JSON output from two Django models. I've already created two serialized views. The output JSON should be:
{
"movie_id": 2,
"total_comments": 4,
"rank": 1
},
{
"movie_id": 3,
"total_comments": 2,
"rank": 2
},
{
"movie_id": 4,
"total_comments": 2,
"rank": 2
}
And the GET /top url should:
Should return top movies already present in the database ranking based on a number of comments added to the movie (as in the example) in the specified date range. The response should include the ID of the movie, position in rank and total number of comments (in the specified date range).
Movies with the same number of comments should have the same position in the ranking.
Should require specifying a date range for which statistics should be generated.
I have two serializers:
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model= Comment
fields=('movie','user','timestamp','content','approved')
class MovieSerializer(DynamicFieldsModelSerializer,serializers.HyperlinkedModelSerializer):
comments=CommentSerializer(many=True)
comments=None
class Meta:
model = Movie
fields = ('id','name','description','year','released','comments','rating')
This is Comment model:
class Comment(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.DO_NOTHING,related_name='comments',blank=True,null=True)
content = models.TextField()
timestamp = models.DateTimeField(default=timezone.now)
user=models.CharField(max_length=250)
I tried to do that on my own by this trick:
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
class TopViewSet(viewsets.ModelViewSet):
serializer_class = MovieSerializer
#queryset = Movie.objects.annotate(comment_count=(Count('comments'))).order_by("-comment_count","-rating")
queryset = Movie.objects.all().annotate(comment_count=(Count('comments'))).order_by("-comment_count")
But I have no idea how to create customized JSON output
If someone could help me also in the last point, i.e. date, I would be grateful.
Upvotes: 0
Views: 173
Reputation: 51988
I think you can do it like this:
# serializer
class MovieSerializer(HyperlinkedModelSerializer):
comments = CommentSerializer(many=True)
comments_count = serializer.IntegerField()
rank = serializer.IntegerField()
class Meta:
model = Movie
fields = ('id','name','description','year','released','comments','rating', 'comments_count', 'rank')
# Viewset
from django.db.models import Sum, F
from django.db.models.expressions import Window
from django.db.models.functions import Rank
class TopViewSet(viewsets.ModelViewSet):
serializer_class = MovieSerializer
queryset = Movie.objects.all()
def get_queryset(self, *args, **kwargs):
from_date = self.request.query_params.get('from_date')
to_date = self.request.query_params.get('to_date')
movies = super(ToViewSet, self).get_queryset()
if from_date and to_date:
movies = movies.filter(release__range=[from_date, to_date])
return movies.annotate(comment_count=Count('comments'), rank=Window(expression=Rank(), order_by=F('comments').desc()),)
In get_queryset()
method, I have use self.request.query_params.get(...)
. This is used to get URL Querystring
. So when you call /your_url/?from_date=2018-01-01&to_date=2019-01-31
, it will filter queryset between the given date range.
Also, I have used Window Function
of Django model to annotate rank of the objects.
Finally, in the serializer I have added 2 extra fields in Serializer
. It will capture the annotated values from the queryset and display as output.
Upvotes: 1
Reputation: 73
i think you should rewrite get method in your view:
from rest_framework.response import Response
from rest_framework import status
class MovieViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
def get(self):
""" do some thing"""
output = {{
"movie_id": 2,
"total_comments": 4,
"rank": 1
},
{
"movie_id": 3,
"total_comments": 2,
"rank": 2
},
{
"movie_id": 4,
"total_comments": 2,
"rank": 2
}
}
return Response(output, status=status.HTTP_200_OK)
for more detailes read DRF doc: https://www.django-rest-framework.org/api-guide/generic-views/#generic-views
Upvotes: 0