diff --git a/graphene_django/rest_framework/models.py b/graphene_django/rest_framework/models.py index 848837b79..06d9b60dd 100644 --- a/graphene_django/rest_framework/models.py +++ b/graphene_django/rest_framework/models.py @@ -4,3 +4,8 @@ class MyFakeModel(models.Model): cool_name = models.CharField(max_length=50) created = models.DateTimeField(auto_now_add=True) + + +class MyFakeModelWithPassword(models.Model): + cool_name = models.CharField(max_length=50) + password = models.CharField(max_length=50) diff --git a/graphene_django/rest_framework/mutation.py b/graphene_django/rest_framework/mutation.py index 5e343aa77..93037f690 100644 --- a/graphene_django/rest_framework/mutation.py +++ b/graphene_django/rest_framework/mutation.py @@ -27,6 +27,8 @@ def fields_for_serializer(serializer, only_fields, exclude_fields, is_input=Fals name in exclude_fields # or # name in already_created_fields + ) or ( + field.write_only and not is_input # don't show write_only fields in Query ) if is_not_in_only or is_excluded: @@ -138,6 +140,7 @@ def perform_mutate(cls, serializer, info): kwargs = {} for f, field in serializer.fields.items(): - kwargs[f] = field.get_attribute(obj) + if not field.write_only: + kwargs[f] = field.get_attribute(obj) return cls(errors=None, **kwargs) diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index 4dccc1828..a0c861d6a 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -7,7 +7,7 @@ from rest_framework import serializers from ...types import DjangoObjectType -from ..models import MyFakeModel +from ..models import MyFakeModel, MyFakeModelWithPassword from ..mutation import SerializerMutation @@ -86,6 +86,47 @@ class Meta: assert "created" not in MyMutation.Input._meta.fields +@mark.django_db +def test_write_only_field(): + class WriteOnlyFieldModelSerializer(serializers.ModelSerializer): + password = serializers.CharField(write_only=True) + + class Meta: + model = MyFakeModelWithPassword + fields = ["cool_name", "password"] + + class MyMutation(SerializerMutation): + class Meta: + serializer_class = WriteOnlyFieldModelSerializer + + result = MyMutation.mutate_and_get_payload( + None, mock_info(), **{"cool_name": "New Narf", "password": "admin"} + ) + + assert hasattr(result, "cool_name") + assert not hasattr(result, "password"), "'password' is write_only field and shouldn't be visible" + + +@mark.django_db +def test_write_only_field_using_extra_kwargs(): + class WriteOnlyFieldModelSerializer(serializers.ModelSerializer): + class Meta: + model = MyFakeModelWithPassword + fields = ["cool_name", "password"] + extra_kwargs = {"password": {"write_only": True}} + + class MyMutation(SerializerMutation): + class Meta: + serializer_class = WriteOnlyFieldModelSerializer + + result = MyMutation.mutate_and_get_payload( + None, mock_info(), **{"cool_name": "New Narf", "password": "admin"} + ) + + assert hasattr(result, "cool_name") + assert not hasattr(result, "password"), "'password' is write_only field and shouldn't be visible" + + def test_nested_model(): class MyFakeModelGrapheneType(DjangoObjectType): class Meta: