mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 17:47:04 +03:00
Fix nested write of non-relational fields (#6916)
This commit is contained in:
parent
0dac98d215
commit
30e56f62ba
|
@ -790,6 +790,8 @@ def raise_errors_on_nested_writes(method_name, serializer, validated_data):
|
|||
* Silently ignore the nested part of the update.
|
||||
* Automatically create a profile instance.
|
||||
"""
|
||||
ModelClass = serializer.Meta.model
|
||||
model_field_info = model_meta.get_field_info(ModelClass)
|
||||
|
||||
# Ensure we don't have a writable nested field. For example:
|
||||
#
|
||||
|
@ -799,6 +801,7 @@ def raise_errors_on_nested_writes(method_name, serializer, validated_data):
|
|||
assert not any(
|
||||
isinstance(field, BaseSerializer) and
|
||||
(field.source in validated_data) and
|
||||
(field.source in model_field_info.relations) and
|
||||
isinstance(validated_data[field.source], (list, dict))
|
||||
for field in serializer._writable_fields
|
||||
), (
|
||||
|
@ -817,9 +820,19 @@ def raise_errors_on_nested_writes(method_name, serializer, validated_data):
|
|||
# class UserSerializer(ModelSerializer):
|
||||
# ...
|
||||
# address = serializer.CharField('profile.address')
|
||||
#
|
||||
# Though, non-relational fields (e.g., JSONField) are acceptable. For example:
|
||||
#
|
||||
# class NonRelationalPersonModel(models.Model):
|
||||
# profile = JSONField()
|
||||
#
|
||||
# class UserSerializer(ModelSerializer):
|
||||
# ...
|
||||
# address = serializer.CharField('profile.address')
|
||||
assert not any(
|
||||
len(field.source_attrs) > 1 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))
|
||||
for field in serializer._writable_fields
|
||||
), (
|
||||
|
|
|
@ -4,6 +4,8 @@ from django.http import QueryDict
|
|||
from django.test import TestCase
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework.compat import postgres_fields
|
||||
from rest_framework.serializers import raise_errors_on_nested_writes
|
||||
|
||||
|
||||
class TestNestedSerializer:
|
||||
|
@ -302,3 +304,50 @@ class TestNestedWriteErrors(TestCase):
|
|||
'serializer `tests.test_serializer_nested.DottedAddressSerializer`, '
|
||||
'or set `read_only=True` on dotted-source serializer fields.'
|
||||
)
|
||||
|
||||
|
||||
if postgres_fields:
|
||||
class NonRelationalPersonModel(models.Model):
|
||||
"""Model declaring a postgres JSONField"""
|
||||
data = postgres_fields.JSONField()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not postgres_fields, reason='psycopg2 is not installed')
|
||||
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 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'}}
|
||||
raise_errors_on_nested_writes('create', serializer, serializer.validated_data)
|
||||
raise_errors_on_nested_writes('update', serializer, serializer.validated_data)
|
||||
|
||||
def test_dotted_source_field_create_and_update(self):
|
||||
|
||||
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'}}
|
||||
raise_errors_on_nested_writes('create', serializer, serializer.validated_data)
|
||||
raise_errors_on_nested_writes('update', serializer, serializer.validated_data)
|
||||
|
|
Loading…
Reference in New Issue
Block a user