From 23efdb8489d224cbb53bb20fd8ec3aca1d4539dc Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Wed, 8 Jan 2020 03:31:02 +0100 Subject: [PATCH 1/9] use `to_represenation` in favor of `get_attribute` --- graphene_django/rest_framework/mutation.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/graphene_django/rest_framework/mutation.py b/graphene_django/rest_framework/mutation.py index 060b37009..3009c06ae 100644 --- a/graphene_django/rest_framework/mutation.py +++ b/graphene_django/rest_framework/mutation.py @@ -137,10 +137,5 @@ def mutate_and_get_payload(cls, root, info, **input): @classmethod def perform_mutate(cls, serializer, info): obj = serializer.save() - - kwargs = {} - for f, field in serializer.fields.items(): - if not field.write_only: - kwargs[f] = field.get_attribute(obj) - + kwargs = serializer.to_representation(obj) return cls(errors=None, **kwargs) From e33a6002bfcf411210f52d5a1bce6c3919da1bce Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Wed, 8 Jan 2020 13:35:38 +0100 Subject: [PATCH 2/9] fix datetime type does get converted to a string to_representation will convert the datetime field into a string representation. However the to_representation on the method field will only call its underlying method. --- graphene_django/rest_framework/mutation.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/graphene_django/rest_framework/mutation.py b/graphene_django/rest_framework/mutation.py index 3009c06ae..f9b074d9e 100644 --- a/graphene_django/rest_framework/mutation.py +++ b/graphene_django/rest_framework/mutation.py @@ -137,5 +137,13 @@ def mutate_and_get_payload(cls, root, info, **input): @classmethod def perform_mutate(cls, serializer, info): obj = serializer.save() - kwargs = serializer.to_representation(obj) + + kwargs = {} + for f, field in serializer.fields.items(): + if not field.write_only: + if isinstance(field, serializers.SerializerMethodField): + kwargs[f] = field.to_representation(obj) + else: + kwargs[f] = field.get_attribute(obj) + return cls(errors=None, **kwargs) From 59da509bfb46d76f13c552551409bb1d4abe5758 Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Wed, 8 Jan 2020 13:36:52 +0100 Subject: [PATCH 3/9] fix add missing import --- graphene_django/rest_framework/mutation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphene_django/rest_framework/mutation.py b/graphene_django/rest_framework/mutation.py index f9b074d9e..8985dfe25 100644 --- a/graphene_django/rest_framework/mutation.py +++ b/graphene_django/rest_framework/mutation.py @@ -1,6 +1,7 @@ from collections import OrderedDict from django.shortcuts import get_object_or_404 +from rest_framework import serializers import graphene from graphene.relay.mutation import ClientIDMutation From adc22b559c710ce4a9594e0003df01c34b0728fa Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Wed, 8 Jan 2020 23:31:47 +0100 Subject: [PATCH 4/9] apply black formatter --- graphene_django/rest_framework/mutation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene_django/rest_framework/mutation.py b/graphene_django/rest_framework/mutation.py index 8985dfe25..c3d0c9e83 100644 --- a/graphene_django/rest_framework/mutation.py +++ b/graphene_django/rest_framework/mutation.py @@ -138,7 +138,7 @@ def mutate_and_get_payload(cls, root, info, **input): @classmethod def perform_mutate(cls, serializer, info): obj = serializer.save() - + kwargs = {} for f, field in serializer.fields.items(): if not field.write_only: @@ -146,5 +146,5 @@ def perform_mutate(cls, serializer, info): kwargs[f] = field.to_representation(obj) else: kwargs[f] = field.get_attribute(obj) - + return cls(errors=None, **kwargs) From 380310c60bfb3ca48ce3c2275c53b3e703c87024 Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Sat, 15 Feb 2020 13:29:51 +0100 Subject: [PATCH 5/9] add test for serializer method field --- graphene_django/rest_framework/models.py | 5 +++ .../rest_framework/tests/test_mutation.py | 34 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/graphene_django/rest_framework/models.py b/graphene_django/rest_framework/models.py index 06d9b60dd..86a241d57 100644 --- a/graphene_django/rest_framework/models.py +++ b/graphene_django/rest_framework/models.py @@ -9,3 +9,8 @@ class MyFakeModel(models.Model): class MyFakeModelWithPassword(models.Model): cool_name = models.CharField(max_length=50) password = models.CharField(max_length=50) + + +class MyFakeModelWithDate(models.Model): + cool_name = models.CharField(max_length=50) + last_edited = models.DateField() \ No newline at end of file diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index bfb247da6..b9928a014 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -8,7 +8,7 @@ from ...settings import graphene_settings from ...types import DjangoObjectType -from ..models import MyFakeModel, MyFakeModelWithPassword +from ..models import MyFakeModel, MyFakeModelWithPassword, MyFakeModelWithDate from ..mutation import SerializerMutation @@ -33,6 +33,18 @@ class Meta: fields = "__all__" +class MyModelSerializerWithMethod(serializers.ModelSerializer): + days_since_last_edit = serializers.SerializerMethodField() + + class Meta: + model = MyFakeModelWithDate + fields = "__all__" + + def get_days_since_last_edit(self, obj): + now = datetime.date.fromisoformat("2020-01-08") + return (now - obj.last_edited).days + + class MyModelMutation(SerializerMutation): class Meta: serializer_class = MyModelSerializer @@ -208,6 +220,26 @@ class Meta: assert '"id" required' in str(exc.value) +@mark.django_db +def test_perform_mutate_success(): + class MyMethodMutation(SerializerMutation): + class Meta: + serializer_class = MyModelSerializerWithMethod + + result = MyMethodMutation.mutate_and_get_payload( + None, + mock_info(), + **{ + "cool_name": "Narf", + "last_edited": datetime.date.fromisoformat("2020-01-04"), + } + ) + + assert result.errors is None + assert result.cool_name == "Narf" + assert result.days_since_last_edit == 4 + + def test_mutate_and_get_payload_error(): class MyMutation(SerializerMutation): class Meta: From a61ee3f03da0e191fb66b4490a55848bf12f819d Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Sat, 15 Feb 2020 13:34:13 +0100 Subject: [PATCH 6/9] apply black format --- graphene_django/rest_framework/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/rest_framework/models.py b/graphene_django/rest_framework/models.py index 86a241d57..bd84ce547 100644 --- a/graphene_django/rest_framework/models.py +++ b/graphene_django/rest_framework/models.py @@ -13,4 +13,4 @@ class MyFakeModelWithPassword(models.Model): class MyFakeModelWithDate(models.Model): cool_name = models.CharField(max_length=50) - last_edited = models.DateField() \ No newline at end of file + last_edited = models.DateField() From 3dcdc01cd1b509dcc8f056a65481ae6ce707b5c3 Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Sat, 15 Feb 2020 13:51:11 +0100 Subject: [PATCH 7/9] improve backward compatibility by using date's class contructor instead of fromisostring --- graphene_django/rest_framework/tests/test_mutation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index b9928a014..46d72abfa 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -41,7 +41,7 @@ class Meta: fields = "__all__" def get_days_since_last_edit(self, obj): - now = datetime.date.fromisoformat("2020-01-08") + now = datetime.date(2020, 1, 8) return (now - obj.last_edited).days @@ -231,7 +231,7 @@ class Meta: mock_info(), **{ "cool_name": "Narf", - "last_edited": datetime.date.fromisoformat("2020-01-04"), + "last_edited": datetime.date(2020, 1, 4), } ) From efe3bcf9b8d99da17bb722c5fdce453208b77019 Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Sat, 15 Feb 2020 13:53:24 +0100 Subject: [PATCH 8/9] apply black format --- graphene_django/rest_framework/tests/test_mutation.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index 46d72abfa..a594fc2b5 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -229,10 +229,7 @@ class Meta: result = MyMethodMutation.mutate_and_get_payload( None, mock_info(), - **{ - "cool_name": "Narf", - "last_edited": datetime.date(2020, 1, 4), - } + **{"cool_name": "Narf", "last_edited": datetime.date(2020, 1, 4),} ) assert result.errors is None From 474390afff1818ec4534ddd97265d0ea9f38cf3b Mon Sep 17 00:00:00 2001 From: B4rtware <34386047+B4rtware@users.noreply.github.com> Date: Tue, 18 Feb 2020 00:54:37 +0100 Subject: [PATCH 9/9] fix black format issue --- graphene_django/rest_framework/tests/test_mutation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index a594fc2b5..32f1e2845 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -229,7 +229,7 @@ class Meta: result = MyMethodMutation.mutate_and_get_payload( None, mock_info(), - **{"cool_name": "Narf", "last_edited": datetime.date(2020, 1, 4),} + **{"cool_name": "Narf", "last_edited": datetime.date(2020, 1, 4)} ) assert result.errors is None