Escher
Escher

Reputation: 5776

DRF's CurrentUserDefault isn't returning a user

I have a ModelSerializer. I was trying to set a user foreign key when saving a model, instantiated via the create() and update() methods of a ModelViewSet class. Eg:

ModelViewSet:

def create(self, request):
    serializer = self.get_serializer(data=request.data, many=isinstance(request.data, list))
    if not serializer.is_valid():
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    serializer.save()
    return Response(serializer.data, status=status.HTTP_201_CREATED)

Serializer

def process_foreign_keys(self, validated_data):
    """ Simplified for SO example """
    profile = get_object_or_404(Profile, fk_user=CurrentUserDefault())
    validated_data['profile'] = profile
    return validated_data

def create(self, validated_data):
    """ Create a Product instance. Routed from POST via DRF's serializer """
    validated_data = self.process_foreign_keys(validated_data)
    return Product.objects.create(**validated_data)

That code doesn't work - it throws an exception on the get_object_or_404 line:

int() argument must be a string, a bytes-like object or a number, not 'CurrentUserDefault'

If I put a few debugging statements in the ModelSerializer.create() method, I get weird stuff:

currentuser = CurrentUserDefault()

# Expect <class django.contrib.auth.models.User>, get <class 'rest_framework.fields.CurrentUserDefault'>
print("currentuser type " + str(type(currentuser)))

# Causes AttributeError: 'CurrentUserDefault' object has no attribute 'user' 
print("currentuser is " + str(currentuser.__call__()))

# Causes AttributeError: 'ProductSerializer' object has no attribute 'request'
print("currentuser is " + str(self.request.user))

All this was done while a user was logged in, so it's not an AnonymousUser problem.

What am I screwing up? How do I get the current user in a serializer instantiated within the create/update methods of a ModelViewSet via self.get_serializer()?

Edit: Attempting with a HiddenField doesn't seem to work either. From the docs :

"HiddenField: This field will be present in validated_data but will not be used in the serializer output representation."

So I set as a ModelSerializer class field:

currentuser = serializers.HiddenField(default=serializers.CurrentUserDefault())

... and then attempt validated_data.get('currentuser') in the update method, and that returns None.

Upvotes: 2

Views: 1659

Answers (2)

pramod
pramod

Reputation: 1493

def create(self, request):
    serializer = self.get_serializer(data=request.data, many=isinstance(request.data, list), context={"request": request})

can you change you serializer instantiation to above code and use it as below:

profile = get_object_or_404(Profile, fk_user=self.request.user)

Upvotes: 1

Linovia
Linovia

Reputation: 20976

CurrentUserDefault is not a magic method that gets the user out of the void. It has to be within the context of a field a shown in the documentation

As @pramod pointed out, you need to either:

get_object_or_404(Profile, fk_user=self.request.user)

or set a CurrentUserDefault as a default value for a field.

Upvotes: 1

Related Questions