Skip to content

Mutations with Django User as SimpleLazyObject throw an error #22

Closed
@alecklandgraf

Description

@alecklandgraf

Upgrading to graphene 1.0 and graphene-django, a mutation I have started throwing an error. Note, queries don't throw the error. None of the django examples incorporate a user object, one with a mutation would be great.

Received incompatible instance "[email protected]"."

https://github.com/graphql-python/graphene-django/blob/master/graphene_django/types.py#L105

I started debugging and found that Django is using the SimpleLazyObject to represent users since they may or may not be anonymous, which is causing DjangoObjectType.is_type_of to throw the error.

The call to is_valid_django_model doesn't pass since SimpeLazyObject isn't a class according to inspect.isclass(model) and the error is raised.

I thought about trying to reify the SimpleLazyObject to the User, talked about here, but decided to just override the is_type_of classmethod for my UserNode.

I'm not super happy with this, since I'm not sure what is_valid_django_model is trying to catch.

class UserNode(DjangoObjectType):
    """Graphene object for User."""

    class Meta:
        model = User
        only_fields = ('first_name', 'last_name', 'email', 'profile')
        filter_fields = ['first_name', 'last_name', 'email']
        filter_order_by = ['first_name']
        interfaces = (Node, )

    @classmethod
    def is_type_of(cls, root, context, info):
        """Override `is_type_of` to take care of django's SimpleLazyObject for the User model in mutations."""
        if isinstance(root, cls):
            return True
        model = root._meta.model
        return model == cls._meta.model

Here's the mutation (stripped down) that was throwing the error:

from graphql_relay.node.node import from_global_id
Rid = namedtuple('Rid', 'name id')

class IntroduceAirplane(relay.ClientIDMutation):
    """Mutation to add and edit airplanes"""

    class Input:
        name = graphene.String()
        id = graphene.String()

    airplane = graphene.Field(AirplaneNode)

    @classmethod
    def mutate_and_get_payload(cls, input, context, info):
        """Method to clean the input and create a rebate."""
        if not context.user.is_authenticated():
            raise Exception('User is not logged in.')

        pk = input.get('id')

        if pk:
            rid = Rid(*from_global_id(pk))
            input.pop('id', None)
            Airplane.objects.filter(pk=rid.id).update(**input)
            airplane = Airplane.objects.get(pk=rid.id)
        else:
            airplane = Airplane.objects.create(created_by=context.user, **input)

        return IntroduceAirplane(airplane=airplane)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions