Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework: Change Serializer or Add Field Based on Authentication

I have a viewset as follows:

class CardViewSet(viewsets.ReadOnlyModelViewSet):
    """
    Standard Viewset for listing cards
    """
    pagination_class = StandardCellSetPagination
    permission_classes = [AllowAny, IsAuthenticated]

    def list(self, request):
        queryset = Card.objects.exclude(reply_to__isnull=False).order_by('-created')
        cards = self.paginate_queryset(queryset)
        serializer = CardCellSerializer(cards, many=True)
        return self.get_paginated_response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = Card.objects.all()
        card = get_object_or_404(queryset, pk=pk)
        serializer = CardSerializer(card)
        return Response(serializer.data)

My serializer for the CardSerializer is:

class CardSerializer(serializers.ModelSerializer):
    class Meta:
        model = Card

How do I either

  • Change the serializer for the retrieve method if the viewset has the permission IsAuthenticated? OR
  • Add a field to the CardSerializer if viewset has IsAuthenticated?

Such that I can return True / False if a user has favorited the card via a SerializerMethodField

like image 533
blue_zinc Avatar asked Oct 17 '25 23:10

blue_zinc


1 Answers

You can do this:

def retrieve(self, request, pk=None):
    queryset = Card.objects.all()
    card = get_object_or_404(queryset, pk=pk)

    # Same for list method
    if request.user and request.user.is_authenticated:
        serializer = AuthenticatedCardSerializer(card)
    else:
        serializer = CardSerializer(card)

    return Response(serializer.data)

AuthenticatedCardSerializer could then extend CardSerializer to include any fields visible to authenticated users.

Also if you decide to use same serialization behavior for list and retrieve, you could override get_serializer_class in your viewset instead:

def get_serializer_class(self):
    if self.request.user and self.request.user.is_authenticated:
        return AuthenticatedCardSerializer
    else:
        return CardSerializer

and leave everything else to the default list/retrieve implementations.

As an alternative, you could add the field in serializer's __init__. You can get the request from the context kwarg, do the same check and add any fields you need. I think though that it is needlessly more complicated than just having two serializers.

like image 62
Ivan Avatar answered Oct 19 '25 13:10

Ivan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!