Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Current User inside nested serializer

I'm using Django Rest Framework 3.3.2 with Django 1.9.1 I have 2 serializers and I use one of them inside the other one.

class VideoSerializer(serializers.ModelSerializer):
current_username = serializers.SerializerMethodField()
is_deletable = serializers.SerializerMethodField()
tagged_users = EachUserSerializer(many=True, read_only=True)
print current_username
comments = CommentSerializer(many=True, read_only=True, context={'current_username': current_username})
place_taken = PlaceLimitedSerializer()
owner_user = EachUserSerializer()

class Meta:
    model = Video
    fields = ('tagged_users', 'comments', 'place_taken', 'video_id', 'video_url', 'like_count', 'caption', 'date',
              'category', 'owner_user', 'current_username', 'is_deletable', )

def get_current_username(self, obj):
    self.current_username = self.context['request'].user.username
    return self.context['request'].user.username

def get_is_deletable(self, obj):

    return obj.is_deletable_by(self.current_username)



class CommentSerializer(serializers.ModelSerializer):
current_username = serializers.SerializerMethodField()
is_deletable = serializers.SerializerMethodField()
is_editable = serializers.SerializerMethodField()

def get_current_username(self, obj):
    self.current_username = self.context['current_username']
    return self.current_username

def get_is_deletable(self, obj):
    return obj.is_deletable(self.current_username)

def get_is_editable(self, obj):
    return obj.is_editable(self.current_username)

class Meta:
    model = Comment
    fields = ('comment', 'username', 'comment_id', 'date', 'current_username', 'is_editable', 'is_deletable',)

My question is that I need current user's username in serializers. I managed to do that in VideoSerializer by setting a context in view like this.

class get_video(APIView):

def get(self, request):
    video_id = str(request.query_params.get('video_id'))
    if Video.objects.all().filter(video_id=video_id).exists():
        video = Video.objects.get(video_id=video_id)
        serializer = VideoSerializer(video, context={"request": request})
        return JsonResponse(serializer.data)
    else:
        return JsonResponse({"result": "no_video"})

In VideoSerializer, I tried to set context and I want to pass 'current_user' to the CommentSerializer but it gives this error.

Internal Server Error: /video/get_video/
Traceback (most recent call last):
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/rest_framework/views.py", line 466, in dispatch
response = self.handle_exception(exc)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/rest_framework/views.py", line 463, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/mcagataybarin/molocate-dev/molocate_eb/video/views.py", line 96, in get
return JsonResponse(serializer.data)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/rest_framework/serializers.py", line 503, in data
ret = super(Serializer, self).data
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/rest_framework/serializers.py", line 239, in data
self._data = self.to_representation(self.instance)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/rest_framework/serializers.py", line 472, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/rest_framework/serializers.py", line 614, in to_representation
self.child.to_representation(item) for item in iterable
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/rest_framework/serializers.py", line 472, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/Users/mcagataybarin/molocate-dev/env/lib/python2.7/site-packages/rest_framework/fields.py", line 1645, in to_representation
return method(value)
File "/Users/mcagataybarin/molocate-dev/molocate_eb/video/serializers.py", line 13, in get_current_username
self.current_username = self.context['current_username']
KeyError: 'current_username'

How can I fix that ? I checked the DRF documentation and also checked the stackoverflow but couldn't find the right answer. I'd appreciate if you help.

like image 600
Çağatay Barın Avatar asked Sep 26 '22 12:09

Çağatay Barın


2 Answers

The context is available for anything that is under the top serializer - i.e. applies to Serializers and Fields as well. Therefore in the CommentSerializer you should have:

self.current_username = self.context['request'].user.username
like image 125
Linovia Avatar answered Sep 28 '22 03:09

Linovia


After a lot of google search, I fixed the problem like this.

class VideoSerializer(serializers.ModelSerializer):
    current_username = serializers.SerializerMethodField()
    is_deletable = serializers.SerializerMethodField()
    tagged_users = EachUserSerializer(many=True, read_only=True)
    comments = serializers.SerializerMethodField()
    place_taken = PlaceLimitedSerializer()
    owner_user = EachUserSerializer()

    class Meta:
        model = Video
        field = ('tagged_users', 'comments', 'place_taken', 'video_id', 'video_url', 'like_count', 'caption', 'date',
                  'category', 'owner_user', 'is_deletable', )

    def get_comments(self, obj):
        serializer_context = {'current_username': self.current_username}
        serializer = CommentSerializer(obj.comments, many=True, read_only=True, context=serializer_context)
        return serializer.data

    def get_current_username(self, obj):
        self.current_username = self.context['request'].user.username
        return self.context['request'].user.username

    def get_is_deletable(self, obj):

        return obj.is_deletable_by(self.current_username)

    class CommentSerializer(serializers.ModelSerializer):
    current_username = serializers.SerializerMethodField()
    is_deletable = serializers.SerializerMethodField()
    is_editable = serializers.SerializerMethodField()

    def get_current_username(self, obj):
        self.current_username = self.context.get('current_username')
        return self.context.get('current_username')

    def get_is_deletable(self, obj):
        return obj.is_deletable(self.current_username)

    def get_is_editable(self, obj):
        return obj.is_editable(self.current_username)

    class Meta:
        model = Comment
        fields = ('comment', 'username', 'comment_id', 'date', 'current_username', 'is_editable', 'is_deletable',)

I serialized the nested serialization inside SerializerMethodField and I've sent the current_username that I extract from context to the nester serializer's context. After doing this problem solved and it works :)

like image 40
Çağatay Barın Avatar answered Sep 28 '22 03:09

Çağatay Barın