Home > Software engineering >  Django REST Framework: How to use prefetched queriesets in child serializers in nested serializers
Django REST Framework: How to use prefetched queriesets in child serializers in nested serializers

Time:10-18

I want to call a queryset prefetched from a View from a nested serializer child. I tried the following but it did not work the way I intended. How can I call a prefetched queryset from a child serializer?

#models.py
class User(AbstractBaseUser, PermissionsMixin):
   ...

#This is allauth.models
class EmailAddress(models.Model):
    user = models.ForeignKey(
        allauth_app_settings.USER_MODEL,
        verbose_name=_("user"),
        on_delete=models.CASCADE,
    )
    verified = models.BooleanField(verbose_name=_("verified"), default=False)
#views.py
class PlaylistListView(generics.ListAPIView):
    serializer_class = PlaylistSerializer

    def get_queryset(self):
        return (
            Playlist.objects.all()
            .prefetch_related("user", "user__emailaddress_set")
        )

#serializers.py
class UserDetailSerializer(serializers.ModelSerializer):
    is_verified = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ("is_verified",)

    def get_is_verified(self, user):
        return user.emailaddress_set.filter(verified=1).count() > 0 # <- here


class PlaylistSerializer(serializers.ModelSerializer):
    user = UserDetailSerializer(read_only=True)

    class Meta:
        model = Playlist
        fields = ("user",)

function max(boolean) does not exist: error image

CodePudding user response:

We can use a Prefetch object to prefetch the users with an annotation for if it is verified or not, verified seems to be a boolean so selecting the Max will give us True if any related emails are verified. In the serializer we can then look for this annotation and if it exists return it otherwise return the same thing as before

from django.db.models import Prefetch, Max


class PlaylistListView(generics.ListAPIView):
    serializer_class = PlaylistSerializer

    def get_queryset(self):
        return Playlist.objects.prefetch_related(
            Prefetch('user', queryset=User.objects.annotate(_is_verified=Max('emailaddress__verified')))
        )


class UserDetailSerializer(serializers.ModelSerializer):
    is_verified = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ("is_verified",)

    def get_is_verified(self, user):
        if hasattr(user, "_is_verified"):
            return user._is_verified
        else:
            return user.emailaddress_set.filter(verified=True).exists()
  • Related