This commit is contained in:
Frank Pape 2014-03-04 15:42:04 +00:00
commit 3eab347850
4 changed files with 87 additions and 9 deletions

View File

@ -105,7 +105,9 @@ When deserializing data, we can either create a new instance, or update an exist
serializer = CommentSerializer(data=data) # Create new instance
serializer = CommentSerializer(comment, data=data) # Update `comment`
By default, serializers must be passed values for all required fields or they will throw validation errors. You can use the `partial` argument in order to allow partial updates.
When creating a new instance, serializers must be passed values for all required fields or they will throw validation errors.
When updating an existing instance, serializers must be passed values for every field that does not have a default specified, or they will throw validation errors. Omitted fields will be reset to their default values. You can use the `partial` argument in order to allow partial updates, in which case omitted fields will not be changed.
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True) # Update `comment` with partial data

View File

@ -356,7 +356,8 @@ class WritableField(Field):
# Note: partial updates shouldn't set defaults
native = self.get_default_value()
else:
if self.required:
incomplete_update = self.root.object is not None and not self.partial
if self.required or incomplete_update:
raise ValidationError(self.error_messages['required'])
return

View File

@ -43,8 +43,10 @@ class SlugBasedModel(RESTFrameworkModel):
class DefaultValueModel(RESTFrameworkModel):
required_field = models.CharField(max_length=100)
text = models.CharField(default='foobar', max_length=100)
extra = models.CharField(blank=True, null=True, max_length=100)
extra_not_nullable = models.CharField(blank=True, max_length=100)
class CallableDefaultValueModel(RESTFrameworkModel):

View File

@ -867,37 +867,110 @@ class DefaultValueTests(TestCase):
self.objects = DefaultValueModel.objects
def test_create_using_default(self):
data = {}
data = {'required_field': 'required_field_value'}
serializer = self.serializer_class(data=data)
self.assertEqual(serializer.is_valid(), True)
instance = serializer.save()
self.assertEqual(len(self.objects.all()), 1)
self.assertEqual(instance.pk, 1)
self.assertEqual(instance.text, 'foobar')
self.assertEqual(instance.required_field, 'required_field_value')
self.assertEqual(instance.extra, None)
self.assertEqual(instance.extra_not_nullable, '')
def test_create_overriding_default(self):
data = {'text': 'overridden'}
data = {'required_field': 'required_field_value', 'text': 'overridden'}
serializer = self.serializer_class(data=data)
self.assertEqual(serializer.is_valid(), True)
instance = serializer.save()
self.assertEqual(len(self.objects.all()), 1)
self.assertEqual(instance.pk, 1)
self.assertEqual(instance.text, 'overridden')
self.assertEqual(instance.required_field, 'required_field_value')
self.assertEqual(instance.extra, None)
self.assertEqual(instance.extra_not_nullable, '')
def test_partial_update_default(self):
""" Regression test for issue #532 """
data = {'text': 'overridden'}
"""
Regression test for issue #532. Ensure a partial update does not modify omitted
fields to their default values.
"""
data = {
'required_field': 'required_field_value',
'text': 'overridden',
'extra': 'extra_value',
'extra_not_nullable': 'extra_not_nullable_value',
}
serializer = self.serializer_class(data=data, partial=True)
self.assertEqual(serializer.is_valid(), True)
instance = serializer.save()
self.assertEqual(instance.required_field, 'required_field_value')
self.assertEqual(instance.text, 'overridden')
self.assertEqual(instance.extra, 'extra_value')
self.assertEqual(instance.extra_not_nullable, 'extra_not_nullable_value')
data = {'extra': 'extra_value'}
data = {'extra': 'extra_updated'}
serializer = self.serializer_class(instance=instance, data=data, partial=True)
self.assertEqual(serializer.is_valid(), True)
instance = serializer.save()
self.assertEqual(instance.extra, 'extra_value')
self.assertEqual(instance.extra, 'extra_updated')
self.assertEqual(instance.text, 'overridden')
self.assertEqual(instance.required_field, 'required_field_value')
self.assertEqual(instance.extra_not_nullable, 'extra_not_nullable_value')
def test_non_partial_update_default(self):
"""
Omitted values in a full update should be reset.
"""
data = {
'required_field': 'required_field_value',
'text': 'overridden',
'extra': 'extra_value',
'extra_not_nullable': 'extra_not_nullable_value',
}
serializer = self.serializer_class(data=data)
self.assertTrue(serializer.is_valid())
instance = serializer.save()
self.assertEqual(instance.required_field, 'required_field_value')
self.assertEqual(instance.text, 'overridden')
self.assertEqual(instance.extra, 'extra_value')
self.assertEqual(instance.extra_not_nullable, 'extra_not_nullable_value')
# Omitting a required field is not valid.
data = {'text': 'text_updated'}
serializer = self.serializer_class(instance=instance, data=data)
self.assertFalse(serializer.is_valid())
# Omitting an optional field with no default value is not valid
data = {
'text': 'text_updated',
'required_field': 'required_field_updated',
'extra': 'extra_updated',
}
serializer = self.serializer_class(instance=instance, data=data)
self.assertFalse(serializer.is_valid())
data = {
'text': 'text_updated',
'required_field': 'required_field_updated',
'extra_not_nullable': 'extra_not_nullable_updated',
}
serializer = self.serializer_class(instance=instance, data=data)
self.assertFalse(serializer.is_valid())
# A field with a default value should be reset to default when omitted
data = {
'required_field': 'required_field_updated',
'extra': 'extra_updated',
'extra_not_nullable': 'extra_not_nullable_updated',
}
serializer = self.serializer_class(instance=instance, data=data)
self.assertTrue(serializer.is_valid())
instance = serializer.save()
self.assertEqual(instance.text, 'foobar')
self.assertEqual(instance.required_field, 'required_field_updated')
self.assertEqual(instance.extra, 'extra_updated')
self.assertEqual(instance.extra_not_nullable, 'extra_not_nullable_updated')
class WritableFieldDefaultValueTests(TestCase):