Search code examples
djangomongodbgraphene-django

I am trying to create a graphql mutation , where i cannot add the categoryNode as a input feild to AddEquipment mutation


category model this my category model

class Category(models.Model):
    _id = models.ObjectIdField(primary_key=True)
    name = models.CharField(max_length=100)

Category node I've created a category node using relay

class CategoryNode(DjangoObjectType):
    class Meta:
        model = Category
        filter_fields = ['name', 'equipments']
        interfaces = (relay.Node,)

add equipmemt mutation while mutation i need to add a category object to equipment object in mutation inputs

class AddEquipment(relay.ClientIDMutation):
    class Input:
        name = graphene.String(required=True)
        category = graphene.Field(CategoryNode)

    equipment = graphene.Field(EquipmentNode)

    @classmethod
    def mutate_and_get_payload(cls, root, info, **inputs):
        equipment_instance = Equipment(
            name=inputs.get('name'),
            category=inputs.get('category')
        )
        equipment_instance.save()
        return AddEquipment(equipment=equipment_instance)

by this code iam getting error like this

"AssertionError: AddEquipmentInput.category field type must be Input Type but got: CategoryNode."


Solution

  • Unfortunately you can't do that as an ObjectType cannot be an InputObjectType. The only way for you to make it work is to create a new class which derived from the InputObjectType.

    class CategoryInput(graphene.InputObjectType):
        id = graphene.ID(required=True)
        name = graphene.String()
    

    and use it.

    class AddEquipment(relay.ClientIDMutation):
        class Input:
            name = graphene.String(required=True)
            category = graphene.Field(CategoryInput, required=True)
    
        ...
    

    UPDATE

    I think in your case, If you only want to get the category instance there would be no point to input a whole detail of category in your mutation so I suggest to only input the name and the category id in your inner class Input and get query a category instance see example inside your mutate_and_get_payload.

    So to be precise you should refactor your code into:

    class AddEquipment(relay.ClientIDMutation):
        class Input:
            name = graphene.String(required=True)
            category_id = graphene.ID(required=True)
    
        equipment = graphene.Field(EquipmentNode)
    
        @classmethod
        def mutate_and_get_payload(cls, root, info, **inputs):
            # if ID is global make sure to extract the int type id.
            # but in this case we assume that you pass an int.
            category_instance = Category.objects.get(id=inputs.get('category_id'))
            equipment_instance = Equipment(
                name=inputs.get('name'),
                category=category_instance
            )
            equipment_instance.save()
            return AddEquipment(equipment=equipment_instance)