Get current user in Model Serializer

PythonDjangoSerializationDjango Rest-Framework

Python Problem Overview


Is it possible to get the current user in a model serializer? I'd like to do so without having to branch away from generics, as it's an otherwise simple task that must be done.

My model:

class Activity(models.Model):
    number = models.PositiveIntegerField(
        blank=True, null=True, help_text="Activity number. For record keeping only.")
    instructions = models.TextField()
    difficulty = models.ForeignKey(Difficulty)
    categories = models.ManyToManyField(Category)
    boosters = models.ManyToManyField(Booster)

    class Meta():
        verbose_name_plural = "Activities"

My serializer:

class ActivitySerializer(serializers.ModelSerializer):
	    
	class Meta:
		model = Activity

And my view:

class ActivityDetail(generics.RetrieveUpdateDestroyAPIView):

    queryset = Activity.objects.all()
    serializer_class = ActivityDetailSerializer

How can I get the model returned, with an additional field user such that my response looks like this:

{
    "id": 1, 
    "difficulty": 1, 
    "categories": [
        1
    ], 
    "boosters": [
        1
    ],
    "current_user": 1 //Current authenticated user here
}

Python Solutions


Solution 1 - Python

I found the answer looking through the DRF source code.

class ActivitySerializer(serializers.ModelSerializer):
	
    # Create a custom method field
	current_user = serializers.SerializerMethodField('_user')

    # Use this method for the custom field
	def _user(self, obj):
        request = self.context.get('request', None)
        if request:
            return request.user

	class Meta:
		model = Activity
        # Add our custom method to the fields of the serializer
		fields = ('id','current_user')

The key is the fact that methods defined inside a ModelSerializer have access to their own context, which always includes the request (which contains a user when one is authenticated). Since my permissions are for only authenticated users, there should always be something here.

This can also be done in other built-in djangorestframework serializers.

As Braden Holt pointed out, if your user is still empty (ie _user is returning None), it may be because the serializer was not initialized with the request as part of the context. To fix this, simply add the request context when initializing the serializer:

serializer = ActivitySerializer(
    data=request.data,
    context={
        'request': request
    }
)

Solution 2 - Python

A context is passed to the serializer in REST framework, which contains the request by default. So you can just use self.context['request'].user inside your serializer.

Solution 3 - Python

I had a similar problem - I tried to save the model that consist user in, and when I tried to use user = serializers.StringRelatedField(read_only=True, default=serializers.CurrentUserDefault()) like on official documentation - but it throws an error that user is 'null'. Rewrite the default create method and get a user from request helped for me:

class FavoriteApartmentsSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField(read_only=True, default=serializers.CurrentUserDefault())

class Meta:
    model = FavoriteApartments
    exclude = (
        'date_added',
    )

def create(self, validated_data):
    favoriteApartment = FavoriteApartments(
        apartment=validated_data['apartment'],
        user=self.context['request'].user
    )
    favoriteApartment.save()
    return favoriteApartment

Solution 4 - Python

I modified the request.data:

serializer = SectionSerializer(data=add_profile_data(request.data, request.user))

def add_profile_data(data, user):
    data['user'] = user.profile.id
    return data

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJamie CounsellView Question on Stackoverflow
Solution 1 - PythonJamie CounsellView Answer on Stackoverflow
Solution 2 - PythoncodwellView Answer on Stackoverflow
Solution 3 - PythonAshen OneView Answer on Stackoverflow
Solution 4 - PythonAndrés M. JiménezView Answer on Stackoverflow