Skip to content

Commit 6d89430

Browse files
Merge pull request #2475 from sdreher/master
ManyRelatedField.get_value clearing field on partial update
2 parents 81c2562 + e7da266 commit 6d89430

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

rest_framework/relations.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,12 @@ def get_value(self, dictionary):
338338
# We override the default field access in order to support
339339
# lists in HTML forms.
340340
if html.is_html_input(dictionary):
341+
# Don't return [] if the update is partial
342+
if self.field_name not in dictionary:
343+
if getattr(self.root, 'partial', False):
344+
return empty
341345
return dictionary.getlist(self.field_name)
346+
342347
return dictionary.get(self.field_name, empty)
343348

344349
def to_internal_value(self, data):

tests/test_relations.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from .utils import mock_reverse, fail_reverse, BadType, MockObject, MockQueryset
22
from django.core.exceptions import ImproperlyConfigured
3+
from django.utils.datastructures import MultiValueDict
34
from rest_framework import serializers
5+
from rest_framework.fields import empty
46
from rest_framework.test import APISimpleTestCase
57
import pytest
68

@@ -134,3 +136,34 @@ def test_slug_related_lookup_invalid_type(self):
134136
def test_representation(self):
135137
representation = self.field.to_representation(self.instance)
136138
assert representation == self.instance.name
139+
140+
141+
class TestManyRelatedField(APISimpleTestCase):
142+
def setUp(self):
143+
self.instance = MockObject(pk=1, name='foo')
144+
self.field = serializers.StringRelatedField(many=True)
145+
self.field.field_name = 'foo'
146+
147+
def test_get_value_regular_dictionary_full(self):
148+
assert 'bar' == self.field.get_value({'foo': 'bar'})
149+
assert empty == self.field.get_value({'baz': 'bar'})
150+
151+
def test_get_value_regular_dictionary_partial(self):
152+
setattr(self.field.root, 'partial', True)
153+
assert 'bar' == self.field.get_value({'foo': 'bar'})
154+
assert empty == self.field.get_value({'baz': 'bar'})
155+
156+
def test_get_value_multi_dictionary_full(self):
157+
mvd = MultiValueDict({'foo': ['bar1', 'bar2']})
158+
assert ['bar1', 'bar2'] == self.field.get_value(mvd)
159+
160+
mvd = MultiValueDict({'baz': ['bar1', 'bar2']})
161+
assert [] == self.field.get_value(mvd)
162+
163+
def test_get_value_multi_dictionary_partial(self):
164+
setattr(self.field.root, 'partial', True)
165+
mvd = MultiValueDict({'foo': ['bar1', 'bar2']})
166+
assert ['bar1', 'bar2'] == self.field.get_value(mvd)
167+
168+
mvd = MultiValueDict({'baz': ['bar1', 'bar2']})
169+
assert empty == self.field.get_value(mvd)

0 commit comments

Comments
 (0)