Graphene-django: DjangoFormMutation and DjangoModelFormMutation ignore provided form_class

Created on 18 Apr 2020  路  4Comments  路  Source: graphql-python/graphene-django

I'm trying to create a simple DjangoModelFormMutation and getting this error when creating the Mutation class:

form_class is required for DjangoModelFormMutation

Update: Applies to both DjangoModelFormMutation and DjangoFormMutation.

# projects/forms.py
class ProjectCreateForm(ModelForm):
    class Meta:
        model = Project
        fields = ("name",)
# projects/schema.py
class ProjectType(DjangoObjectType):
    class Meta:
        model = Project


class ProjectCreateMutation(DjangoModelFormMutation):
    project = graphene.Field(ProjectType)

    class Meta:
        form_class = ProjectCreateForm



md5-a67608c80fd695011bbc99cce974ae3f



# schema.py
class Mutation(projects.schema.ProjectCreateMutation, graphene.ObjectType):
    pass


schema = graphene.Schema(mutation=Mutation)

Using:
graphene-django==2.9.1 but also tried 2.8.2 due to potentially relevant changes introduced in 2.9.0
graphene==2.1.8
django==2.2.12

Feels like I'm missing something obvious, any idea what that might be?

Most helpful comment

Thanks for looking into this.

After digging a deep further, it looks like I was missing an intermediate class.
My Mutation class above is a subclass ofProjectCreateMutation class, but the expected behaviour is to subclass graphene.ObjectType first.

Looking back at the docs, I think the confusion came from this example.
Whilst the simple example includes the mutation subclassing graphene.ObjectType, the Django Form examples don't, so I was under the impression it wasn't needed.

Happy to send a PR if you think it'll help to include this mutation in the Django Form examples.

For completeness, in case someone else bumps into this, here's a working example of the above:

# projects/forms.py
class ProjectCreateForm(ModelForm):
    class Meta:
        model = Project
        fields = ("name",)
# projects/schema.py
class ProjectType(DjangoObjectType):
    class Meta:
        model = Project


class ProjectCreateMutation(DjangoModelFormMutation):
    project = graphene.Field(ProjectType)

    class Meta:
        form_class = ProjectCreateForm


class Mutation(graphene.ObjectType):
    create_project = ProjectCreateMutation.Field()



md5-a67608c80fd695011bbc99cce974ae3f



# schema.py
class Mutation(projects.schema.Mutation, graphene.ObjectType):
    pass


schema = graphene.Schema(mutation=Mutation)

All 4 comments

I can't understand why that won't work. You can see the test that verifies the behaviour here: https://github.com/graphql-python/graphene-django/blob/23b6419b428a0f1b4bd3a8124e49d899b86800a7/graphene_django/forms/tests/test_mutation.py#L199

Can you create a project so that I can reproduce it locally?

Thanks for looking into this.

After digging a deep further, it looks like I was missing an intermediate class.
My Mutation class above is a subclass ofProjectCreateMutation class, but the expected behaviour is to subclass graphene.ObjectType first.

Looking back at the docs, I think the confusion came from this example.
Whilst the simple example includes the mutation subclassing graphene.ObjectType, the Django Form examples don't, so I was under the impression it wasn't needed.

Happy to send a PR if you think it'll help to include this mutation in the Django Form examples.

For completeness, in case someone else bumps into this, here's a working example of the above:

# projects/forms.py
class ProjectCreateForm(ModelForm):
    class Meta:
        model = Project
        fields = ("name",)
# projects/schema.py
class ProjectType(DjangoObjectType):
    class Meta:
        model = Project


class ProjectCreateMutation(DjangoModelFormMutation):
    project = graphene.Field(ProjectType)

    class Meta:
        form_class = ProjectCreateForm


class Mutation(graphene.ObjectType):
    create_project = ProjectCreateMutation.Field()



md5-a67608c80fd695011bbc99cce974ae3f



# schema.py
class Mutation(projects.schema.Mutation, graphene.ObjectType):
    pass


schema = graphene.Schema(mutation=Mutation)

Ah yeah that makes sense. The Mutation type is just a special ObjectType that contains all the mutations in the schema. So it can't be a single mutation.

Glad you figured this out.

Thanks for that @leotsem. This definitely threw me for a loop as well. Now that I better understand how Graphene-Python and Graphene-Django work, it makes complete sense, but I guess I half expected the mutation field to be automatically created based on the class name or something.

At the moment, I think the Django-specific docs make the assumption a user might have a bit more knowledge of Graphene-Python than I approached them with. I think completing the example in the docs as follows would have been helpful to me:

import graphene
from django import forms
from django.db import models
from graphene_django import DjangoObjectType
from graphene_django.forms.mutation import DjangoModelFormMutation

class Pet(models.Model):
    name = models.CharField()

class PetForm(forms.ModelForm):
    class Meta:
        model = Pet
        fields = ('name',)

# This will get returned when the mutation completes successfully
class PetType(DjangoObjectType):
    class Meta:
        model = Pet

class PetMutation(DjangoModelFormMutation):
    pet = Field(PetType)

    class Meta:
        form_class = PetForm

class Mutation(graphene.ObjectType):
    create_pet = PetMutation.Field()

schema = graphene.Schema(mutation=Mutation)
Was this page helpful?
0 / 5 - 0 ratings

Related issues

dan-klasson picture dan-klasson  路  4Comments

khankuan picture khankuan  路  4Comments

amiyatulu picture amiyatulu  路  3Comments

Northshoot picture Northshoot  路  4Comments

licx picture licx  路  3Comments