CurrentUserDefault doesn't work with AnonymousUser

Viewed 33

I'm trying to use CurrentUserDefault with a field that can be null:

# model
class Package(models.Model):
    # User can be empty because we allow anonymous donations
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )

# serializer
class PackageSerializer(serializers.ModelSerializer):
    owner = serializers.HiddenField(default=serializers.CurrentUserDefault())

Everything works fine when a user is logged in. However, if a user is not authenticated I get this:

ValueError at /api/organizations/village/packages/
Cannot assign "<django.contrib.auth.models.AnonymousUser object at 0x7fc97ad6d940>": "Package.owner" must be a "User" instance.

Is there a reason why CurrentUserDefault doesn't work with anonymous users?

P.S. I know I can use this instead of CurrentUserDefault and it will work:

class AuthorizedUserOrNone:
    requires_context = True

    def __call__(self, serializer_field):
        user = serializer_field.context["request"].user
        if user.is_authenticated:
            return user

        return None

    def __repr__(self):
        return "%s()" % self.__class__.__name__
1 Answers

What do you return if user.is_anonymous? Work that out and add that to def __call__(self, serializer_field) and you should be good. CurrentUserDefault does not appear to handle anonymous users.

Try: get_object_or_404(User, fk_user=self.request.user)

This answer provides more helpful context: Django REST Framework - CurrentUserDefault use

Based on what I'm reading in the Traceback, unless you dive deeper into the code base behind the CurrentUserDefault class I don't think there is a standard way of handling this. My limited research has shown me that CurrentUserDefault doesn't appear to be designed to handle anonymous requests (which fits, given the word "User" in the class). The Traceback seems to align with this.

If I am correct, and you're dealing with an edge-case, then more modifications will likely be required to accomplish what you're looking for. Good luck. Sorry I couldn't help with a direct answer.

Note: the above is untested.

See: Django REST documentation

Related