Description
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)