Home > database >  Django REST Framework: I want to resolve n 1 in SerializerMethodField
Django REST Framework: I want to resolve n 1 in SerializerMethodField

Time:10-14

I am trying to create a queryset that returns Boolean from a queryset prefetched with a reverse reference by SerializerMethodField, as shown in the code below. I'm creating one that determines if there is an object for the current user and returns Boolean. However, when I use the prefetched queryset to filter by the current user as shown below, a new queryset is issued instead of the prefetched queryset, and the n 1 problem occurs.

In the following code, how can we save the queryset and return Booelan?

class VideoSerializer(serializers.ModelSerializer):
    is_viewed = serializers.SerializerMethodField()
    is_favorited = serializers.SerializerMethodField()
    is_wl = serializers.SerializerMethodField()

    class Meta:
        model = Video
        fields = (
            "pk",
            "is_viewed",
            "is_favorited",
            "is_wl",
        )

    @staticmethod
    def setup_eager_loading(queryset):
        queryset.prefetch_related('history_set', 'favorite_set')

    def get_is_viewed(self, obj):
        user = self.context["request"].user
        if user.is_authenticated:
            try:
                obj.history_set.get(user=user) # <- here
                return True
            except History.DoesNotExist:
                pass
        return False

    def get_is_favorited(self, obj):
        user = self.context["request"].user
        if user.is_authenticated:
            try:
                obj.favorite_set.get(user=user) # <- here
                return True
            except Favorite.DoesNotExist:
                pass
        return False

    def get_is_wl(self, obj):
        user = self.context["request"].user
        if user.is_authenticated:
            try:
                Track.objects.get(playlist__user=user, playlist__is_wl=True, video=obj)
                return True
            except Track.DoesNotExist:
                pass
        return False

enter image description here

https://docs.djangoproject.com/en/3.2/ref/models/querysets/

I think using subquery and Exists query expression is better option, as 'Utkucan Bıyıklı' suggested.

CodePudding user response:

By reverse reference, i understand you are referring a foreignkey field, in that case you need to use select_related, prefetch_related is used for many-many fields. Based on it you can use any of the below code. make sure to return the queryset.

 @staticmethod
 def setup_eager_loading(queryset):
     #prefetch_related for 'to-many' relationships
     queryset.prefetch_related('history_set', 'favorite_set')
     return quesyset


 @staticmethod
 def setup_eager_loading(queryset):
     #select_related for 'foreign key' relationships 
     queryset = queryset.select_related('history_set', 'favorite_set')
     return queryset
  • Related