mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-03 20:10:10 +03:00
Merge 3c0ea81fcf
into 71ea5b73ce
This commit is contained in:
commit
3eab347850
|
@ -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(data=data) # Create new instance
|
||||||
serializer = CommentSerializer(comment, data=data) # Update `comment`
|
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
|
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True) # Update `comment` with partial data
|
||||||
|
|
||||||
|
|
|
@ -356,7 +356,8 @@ class WritableField(Field):
|
||||||
# Note: partial updates shouldn't set defaults
|
# Note: partial updates shouldn't set defaults
|
||||||
native = self.get_default_value()
|
native = self.get_default_value()
|
||||||
else:
|
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'])
|
raise ValidationError(self.error_messages['required'])
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,10 @@ class SlugBasedModel(RESTFrameworkModel):
|
||||||
|
|
||||||
|
|
||||||
class DefaultValueModel(RESTFrameworkModel):
|
class DefaultValueModel(RESTFrameworkModel):
|
||||||
|
required_field = models.CharField(max_length=100)
|
||||||
text = models.CharField(default='foobar', max_length=100)
|
text = models.CharField(default='foobar', max_length=100)
|
||||||
extra = models.CharField(blank=True, null=True, 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):
|
class CallableDefaultValueModel(RESTFrameworkModel):
|
||||||
|
|
|
@ -867,37 +867,110 @@ class DefaultValueTests(TestCase):
|
||||||
self.objects = DefaultValueModel.objects
|
self.objects = DefaultValueModel.objects
|
||||||
|
|
||||||
def test_create_using_default(self):
|
def test_create_using_default(self):
|
||||||
data = {}
|
data = {'required_field': 'required_field_value'}
|
||||||
serializer = self.serializer_class(data=data)
|
serializer = self.serializer_class(data=data)
|
||||||
self.assertEqual(serializer.is_valid(), True)
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
instance = serializer.save()
|
instance = serializer.save()
|
||||||
self.assertEqual(len(self.objects.all()), 1)
|
self.assertEqual(len(self.objects.all()), 1)
|
||||||
self.assertEqual(instance.pk, 1)
|
self.assertEqual(instance.pk, 1)
|
||||||
self.assertEqual(instance.text, 'foobar')
|
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):
|
def test_create_overriding_default(self):
|
||||||
data = {'text': 'overridden'}
|
data = {'required_field': 'required_field_value', 'text': 'overridden'}
|
||||||
serializer = self.serializer_class(data=data)
|
serializer = self.serializer_class(data=data)
|
||||||
self.assertEqual(serializer.is_valid(), True)
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
instance = serializer.save()
|
instance = serializer.save()
|
||||||
self.assertEqual(len(self.objects.all()), 1)
|
self.assertEqual(len(self.objects.all()), 1)
|
||||||
self.assertEqual(instance.pk, 1)
|
self.assertEqual(instance.pk, 1)
|
||||||
self.assertEqual(instance.text, 'overridden')
|
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):
|
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)
|
serializer = self.serializer_class(data=data, partial=True)
|
||||||
self.assertEqual(serializer.is_valid(), True)
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
instance = serializer.save()
|
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)
|
serializer = self.serializer_class(instance=instance, data=data, partial=True)
|
||||||
self.assertEqual(serializer.is_valid(), True)
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
instance = serializer.save()
|
instance = serializer.save()
|
||||||
|
self.assertEqual(instance.extra, 'extra_updated')
|
||||||
self.assertEqual(instance.extra, 'extra_value')
|
|
||||||
self.assertEqual(instance.text, 'overridden')
|
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):
|
class WritableFieldDefaultValueTests(TestCase):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user