graphql-python / graphql-python/graphene-django
Cannot use SerializerMutation with model's id
- Dominant language
- Python
- Stars
- 4.4k
- Forks
- 760
- PR merge metrics
- No merged PRs in 30d
Description
**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
]
)
...
```
Contributor guide
Assessment
This issue has not been assessed yet.