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?
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)
Most helpful comment
Thanks for looking into this.
After digging a deep further, it looks like I was missing an intermediate class.
My
Mutationclass above is a subclass ofProjectCreateMutationclass, but the expected behaviour is to subclassgraphene.ObjectTypefirst.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: