Saturday, 26 November 2022

Is there a way to add custom data into ListAPIView in django rest framework

So I've built an API for movies dataset which contain following structure:

Models.py

class Directors(models.Model):
    id = models.IntegerField(primary_key=True)
    first_name = models.CharField(max_length=100, blank=True, null=True)
    last_name = models.CharField(max_length=100, blank=True, null=True)

    class Meta:
        db_table = 'directors'
        ordering = ['-id']

class Movies(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=100, blank=True, null=True)
    year = models.IntegerField(blank=True, null=True)
    rank = models.FloatField(blank=True, null=True)

    class Meta:
        db_table = 'movies'       
        ordering = ['-id']

class Actors(models.Model):
    id = models.IntegerField(primary_key=True)
    first_name = models.CharField(max_length=100, blank=True, null=True)
    last_name = models.CharField(max_length=100, blank=True, null=True)
    gender = models.CharField(max_length=20, blank=True, null=True)

    class Meta:
        db_table = 'actors'       
        ordering = ['-id']

class DirectorsGenres(models.Model):
    director = models.ForeignKey(Directors,on_delete=models.CASCADE,related_name='directors_genres')
    genre = models.CharField(max_length=100, blank=True, null=True)
    prob = models.FloatField(blank=True, null=True)    

    class Meta:
        db_table = 'directors_genres'       
        ordering = ['-director']

class MoviesDirectors(models.Model):
    director = models.ForeignKey(Directors,on_delete=models.CASCADE,related_name='movies_directors')
    movie = models.ForeignKey(Movies,on_delete=models.CASCADE,related_name='movies_directors')
    class Meta:
        db_table = 'movies_directors'       
        ordering = ['-director']
        


class MoviesGenres(models.Model):
    movie = models.ForeignKey(Movies,on_delete=models.CASCADE,related_name='movies_genres')
    genre = models.CharField(max_length=100, blank=True, null=True)    

    class Meta:
        db_table = 'movies_genres'        
        ordering = ['-movie']


class Roles(models.Model):
    actor = models.ForeignKey(Actors,on_delete=models.CASCADE,related_name='roles')
    movie = models.ForeignKey(Movies,on_delete=models.CASCADE,related_name='roles')    
    role = models.CharField(max_length=100, blank=True, null=True)    

    class Meta:
        db_table = 'roles'        
        ordering = ['-actor']

urls.py

from django.urls import path, include
from . import views
from api.views import getMovies, getGenres, getActors

urlpatterns = [ 
    path('', views.getRoutes),    
    path('movies/', getMovies.as_view(), name='movies'),    
    path('movies/genres/', getGenres.as_view(), name='genres'),
    path('actor_stats/<pk>', getActors.as_view(), name='actor_stats'),    
]

serializer.py

from rest_framework import serializers
from movies.models import *

class MoviesSerializer(serializers.ModelSerializer):
    class Meta:
        model = Movies
        fields = '__all__'

class DirectorsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Directors
        fields = '__all__'

class ActorsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Actors
        fields = '__all__'

class DirectorsGenresSerializer(serializers.ModelSerializer):
    class Meta:
        model = DirectorsGenres
        fields = '__all__'

class MoviesDirectorsSerializer(serializers.ModelSerializer):
    movie = MoviesSerializer(many = False)
    director = DirectorsSerializer(many = False)
    class Meta:
        model = MoviesDirectors
        fields = '__all__'

class MoviesGenresSerializer(serializers.ModelSerializer):
    movie = MoviesSerializer(many = False)
    class Meta:
        model = MoviesGenres
        fields = '__all__'

class RolesSerializer(serializers.ModelSerializer):
    movie = MoviesSerializer(many = False)
    actor = ActorsSerializer(many = False)
    class Meta:
        model = Roles
        fields = '__all__'

views.py

class getMovies(ListAPIView):
    directors = Directors.objects.all()  
    queryset = MoviesDirectors.objects.filter(director__in=directors)
    serializer_class = MoviesDirectorsSerializer
    pagination_class = CustomPagination
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['director__first_name', 'director__last_name']

class getGenres(ListAPIView):
    movies = Movies.objects.all()  
    queryset = MoviesGenres.objects.filter(movie__in=movies).order_by('-genre')
    serializer_class = MoviesGenresSerializer
    pagination_class = CustomPagination
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['genre']

class getActors(ListAPIView):
    queryset = Roles.objects.all()
    serializer_class = RolesSerializer
    pagination_class = CustomPagination

    def get_queryset(self):
        return super().get_queryset().filter(
            actor_id=self.kwargs['pk']
        )

Now I want to count number of movies by genre that actor with specific pk played in getActors class. Like the number of movies by genre that actor participated in. E.g. Drama: 2, Horror: 3 Right now I am getting the overall count of movies count: 2:

GET /api/actor_stats/17


HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 800480,
            "movie": {
                "id": 105231,
                "name": "Everybody's Business",
                "year": 1993,
                "rank": null
            },
            "actor": {
                "id": 17,
                "first_name": "Luis Roberto",
                "last_name": "Formiga",
                "gender": "M"
            },
            "role": "Grandfather"
        },
        {
            "id": 800481,
            "movie": {
                "id": 242453,
                "name": "OP Pro 88 - Barra Rio",
                "year": 1988,
                "rank": null
            },
            "actor": {
                "id": 17,
                "first_name": "Luis Roberto",
                "last_name": "Formiga",
                "gender": "M"
            },
            "role": "Himself"
        }
    ]
}

What is the optimized way of achieving the following:

  • number_of_movies_by_genre
  • Drama: 2
  • Horror: 3

UPDATE

I was able to add actor id and movie id in serializers:

class RolesSerializer(serializers.ModelSerializer):
    movie = MoviesSerializer(many = False)
    actor = ActorsSerializer(many = False)
    movie_id = serializers.SerializerMethodField()
    actor_id = serializers.SerializerMethodField()
    class Meta:
        model = Roles
        fields = '__all__'

    def get_movie_id(self, obj):        
        return obj.movie_id
        
    def get_actor_id(self, obj):        
        return obj.actor.id

result:

{
    "next": null,
    "previous": null,
    "count": 2,
    "pagenum": null,
    "results": [
        {
            "id": 800480,
            "movie": {
                "id": 105231,
                "name": "Everybody's Business",
                "year": 1993,
                "rank": null
            },
            "actor": {
                "id": 17,
                "first_name": "Luis Roberto",
                "last_name": "Formiga",
                "gender": "M"
            },
            "movie_id": 105231,
            "actor_id": 17,
            "role": "Grandfather"
        },
        {
            "id": 800481,
            "movie": {
                "id": 242453,
                "name": "OP Pro 88 - Barra Rio",
                "year": 1988,
                "rank": null
            },
            "actor": {
                "id": 17,
                "first_name": "Luis Roberto",
                "last_name": "Formiga",
                "gender": "M"
            },
            "movie_id": 242453,
            "actor_id": 17,
            "role": "Himself"
        }
    ]
}

Now I don't know how to even count in how many movies actor with specific id played so to able even go further and get number of movies by genre.



from Is there a way to add custom data into ListAPIView in django rest framework

No comments:

Post a Comment