Graphene-django: Cannot use SerializerMutation with model's id

Created on 18 Mar 2020  路  7Comments  路  Source: graphql-python/graphene-django

SerializerMutation seems to remove id and insert clientMutationId into the mutation input specification.

Therefore, when I try to follow the tutorial at https://docs.graphene-python.org/projects/django/en/latest/mutations/ under Create/Update Operations it cannot work as described: id is not exposed and so it cannot work as a lookup_field.

As such, I cannot find a way to use a SerializerMutation to update based on the instance id. Am I using this correctly? The Django id field is not shadowed by clientMutationID, just removed from the input spec.

From Documentation:

from graphene_django.rest_framework.mutation import SerializerMutation
from .serializers import MyModelSerializer


class AwesomeModelMutation(SerializerMutation):
    class Meta:
        serializer_class = MyModelSerializer
        model_operations = ['create', 'update']
        lookup_field = 'id'

My code:

class CompanyType(DjangoObjectType):
    class Meta:
        model = Company
        fields = '__all__'

class CompanySerializer(serializers.ModelSerializer):
    class Meta:
        model = Company
        # fields = '__all__'
        fields = ['pk', 'id', 'name']

class CompanyMutation(SerializerMutation):
    class Meta:
        serializer_class = CompanySerializer
        lookup_field = 'id'

class Mutation(graphene.ObjectType):
    company = CompanyMutation.Field()

A mutation like the below should work to update the Company instance's name with id=1, but the graphql service does not accept an id.

mutation {
  company(input: {id: 1, name: "Updated Name"}) {
    id
    name
  }
}

Replacing id:1 with clientMutationId:"1" just creates a new Company with the provided name.

If I modify line 38 of rest_framework/mutation.py as follows then it works as I expect it to:

...
def fields_for_serializer(
    serializer,
    only_fields,
    exclude_fields,
    is_input=False,
    convert_choices_to_enum=True,
):
    fields = OrderedDict()
    for name, field in serializer.fields.items():
        is_not_in_only = only_fields and name not in only_fields
        is_excluded = any(
            [
                name in exclude_fields,
                field.write_only
                and not is_input,  # don't show write_only fields in Query
                field.read_only and is_input # don't show read_only fields in Input
                and name not in ['id', 'pk'],  # ADDED TO ALLOW FOR ID-BASED PARTIAL UPDATE
            ]
        )
...

Most helpful comment

As a workaround:

class MySerializer(serializers.ModelSerializer):
    class Meta:
        model = models.MyModel
        fields = '__all__'
        extra_kwargs = {
            'id': {'read_only': False, 'required': False}
        }

All 7 comments

As a workaround:

class MySerializer(serializers.ModelSerializer):
    class Meta:
        model = models.MyModel
        fields = '__all__'
        extra_kwargs = {
            'id': {'read_only': False, 'required': False}
        }

Also facing this issue.

This issue was introduced in #882 as DRF considers primary key fields as read_only.

I ran into the same issue, and was able to get past it using something similar to @hairypalm's fix in his initial post. However, should the solution be for it to work as expected with clientMutationID? Or maybe work with either that or id/pk? I'm new to GraphQL, so I'm all ears for best practices. If it does default to using clientMutationID, the docs would need to be updated I believe.

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

Hi, Looks like the bug fix is now merged, but not released yet. Thanks a lot for the fix. I am wondering if there will be another release with this fix soon?

Would love to see a release with this fix in it thank you!!

Was this page helpful?
0 / 5 - 0 ratings