Fixed dotted write of non-relational fields, plus the related tests

This commit is contained in:
Konstantinos Tselepakis 2019-09-06 00:05:47 +03:00
parent bc5955f031
commit 2d52a0f180
2 changed files with 67 additions and 0 deletions

View File

@ -819,9 +819,21 @@ def raise_errors_on_nested_writes(method_name, serializer, validated_data, model
# class UserSerializer(ModelSerializer): # class UserSerializer(ModelSerializer):
# ... # ...
# address = serializer.CharField('profile.address') # address = serializer.CharField('profile.address')
#
# Though, we can have a dotted field if it is not expressing a model relation.
#
# For example:
#
# class NonRelationalPersonModel(models.Model):
# profile = JSONField()
#
# class UserSerializer(ModelSerializer):
# ...
# address = serializer.CharField('profile.address')
assert not any( assert not any(
len(field.source_attrs) > 1 and len(field.source_attrs) > 1 and
(field.source_attrs[0] in validated_data) and (field.source_attrs[0] in validated_data) and
(field.source_attrs[0] in model_field_info.relations) and
isinstance(validated_data[field.source_attrs[0]], (list, dict)) isinstance(validated_data[field.source_attrs[0]], (list, dict))
for field in serializer._writable_fields for field in serializer._writable_fields
), ( ), (

View File

@ -4,6 +4,9 @@ from django.http import QueryDict
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.compat import postgres_fields
from rest_framework.serializers import raise_errors_on_nested_writes
from rest_framework.utils import model_meta
class TestNestedSerializer: class TestNestedSerializer:
@ -302,3 +305,55 @@ class TestNestedWriteErrors(TestCase):
'serializer `tests.test_serializer_nested.DottedAddressSerializer`, ' 'serializer `tests.test_serializer_nested.DottedAddressSerializer`, '
'or set `read_only=True` on dotted-source serializer fields.' 'or set `read_only=True` on dotted-source serializer fields.'
) )
@pytest.mark.skipif('not postgres_fields')
class TestNestedNonRelationalFieldWrite:
"""
Test that raise_errors_on_nested_writes does not raise `AssertionError` when the
model field is not a relation.
"""
def test_nested_serializer_create_and_update(self):
class NonRelationalPersonModel(models.Model):
"""Model declaring a postgres JSONField"""
data = postgres_fields.JSONField()
class NonRelationalPersonDataSerializer(serializers.Serializer):
occupation = serializers.CharField()
class NonRelationalPersonSerializer(serializers.ModelSerializer):
data = NonRelationalPersonDataSerializer()
class Meta:
model = NonRelationalPersonModel
fields = ['data']
serializer = NonRelationalPersonSerializer(data={'data': {'occupation': 'developer'}})
assert serializer.is_valid()
assert serializer.validated_data == {'data': {'occupation': 'developer'}}
ModelClass = serializer.Meta.model
info = model_meta.get_field_info(ModelClass)
raise_errors_on_nested_writes('create', serializer, serializer.validated_data, info)
raise_errors_on_nested_writes('update', serializer, serializer.validated_data, info)
def test_dotted_source_field_create_and_update(self):
class NonRelationalPersonModel(models.Model):
"""Model declaring a postgres JSONField"""
data = postgres_fields.JSONField()
class DottedNonRelationalPersonSerializer(serializers.ModelSerializer):
occupation = serializers.CharField(source='data.occupation')
class Meta:
model = NonRelationalPersonModel
fields = ['occupation']
serializer = DottedNonRelationalPersonSerializer(data={'occupation': 'developer'})
assert serializer.is_valid()
assert serializer.validated_data == {'data': {'occupation': 'developer'}}
ModelClass = serializer.Meta.model
info = model_meta.get_field_info(ModelClass)
raise_errors_on_nested_writes('create', serializer, serializer.validated_data, info)
raise_errors_on_nested_writes('update', serializer, serializer.validated_data, info)
assert serializer.data == {'occupation': 'developer'}