From 61379205d4cf773b03d6df63535328c9172bbb24 Mon Sep 17 00:00:00 2001 From: HiddenWarrior Date: Sun, 21 Oct 2018 13:59:24 +0200 Subject: [PATCH] adding_appendlist_field: adding tranformitive field --- rest_framework/fields.py | 16 ++++++++++++ rest_framework/serializers.py | 16 +++++++++++- tests/test_model_serializer.py | 47 ++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 70c210c16..fd0e8af13 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1933,3 +1933,19 @@ class ModelField(Field): if is_protected_type(value): return value return self.model_field.value_to_string(obj) + + +class TransformitiveFieldMixin(): + """ + it's an interface to allow any field to change the it's data + from the already database object if using the modelserializer + """ + + def apply_transformation(self, instance, data): + """ + the transformation to be done by the inherited field to do it's work + :param instance: + :param data: + :return: + """ + raise NotImplementedError("apply_tranformation is not implement for this field %s" % self.field_name) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 110ffbfa9..e6f580647 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -29,7 +29,7 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework.compat import Mapping, postgres_fields, unicode_to_repr from rest_framework.exceptions import ErrorDetail, ValidationError -from rest_framework.fields import get_error_detail, set_value +from rest_framework.fields import get_error_detail, set_value, TransformitiveFieldMixin from rest_framework.settings import api_settings from rest_framework.utils import html, model_meta, representation from rest_framework.utils.field_mapping import ( @@ -901,6 +901,20 @@ class ModelSerializer(Serializer): # "HTTP 201 Created" responses. url_field_name = None + def to_internal_value(self, data): + """ + adding functionality of changing data sent by the serializer + by the data inside the instance + :param data: + :return: + """ + fields = self._writable_fields + for field in fields: + if self.instance and isinstance(field, TransformitiveFieldMixin): + field.apply_transformation(self.instance, data) + + return super(ModelSerializer, self).to_internal_value(data) + # Default `create` and `update` behavior... def create(self, validated_data): """ diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index e9ed9957f..cf840b52f 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -1274,3 +1274,50 @@ class Issue6110Test(TestCase): msginitial = ('Got a `TypeError` when calling `Issue6110TestModel.all_objects.create()`.') with self.assertRaisesMessage(TypeError, msginitial): Issue6110ModelSerializer().create({'wrong_param': 'wrong_param'}) + + +class TestTransformitiveField(TestCase): + + def setUp(self): + self.instance = OneFieldModel(char_field="abc") + + def __create_serializer(self,implementor): + + class serializer(serializers.ModelSerializer): + char_field = implementor() + class Meta: + model = OneFieldModel + fields = ('char_field') + return serializer + + def test_adding_transformitive_field_mixin_without_implementing_the_method(self): + + class EmptyImplementor(serializers.TransformitiveFieldMixin,serializers.CharField): + pass + + with self.assertRaises(NotImplementedError): + TestSerializer = self.__create_serializer(EmptyImplementor) + serializer = TestSerializer(instance=self.instance, data={}) + serializer.save() + + def test_adding_transformitive_field_mixin_with_implementing_the_method(self): + + class NonEmptyImplementor(serializers.TransformitiveFieldMixin,serializers.CharField): + def apply_transformation(self, instance, data): + data["char_field"] = data["char_field"][0:1]+instance.char_field[0:1] + + TestSerializer = self.__create_serializer(NonEmptyImplementor) + serializer = TestSerializer(instance=self.instance, data={"char_field":"bb"}) + new_instance = serializer.save() + self.asserEqual(new_instance.char_field,"ba") + + def test_if_no_instance_is_passed_no_errors_would_happen(self): + + class NonEmptyImplementor(serializers.TransformitiveFieldMixin,serializers.CharField): + def apply_transformation(self, instance, data): + data["char_field"] = data["char_field"][0:1]+instance.char_field[0:1] + + TestSerializer = self.__create_serializer(NonEmptyImplementor) + data={"char_field":"bb"} + serializer = TestSerializer() + serializer.to_internal_value(data)