Skip to content

Cannot use SerializerMutation with model's id #906

Open
@hairypalm

Description

@hairypalm

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
            ]
        )
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions