refactored validation of field names and created tests

This commit is contained in:
iamr0b0x 2022-05-29 22:33:49 +01:00
parent 07871b32d2
commit 54ca29dc58
2 changed files with 65 additions and 4 deletions

View File

@ -997,7 +997,7 @@ class ModelSerializer(Serializer):
# relationships as being a special case. During updates we already # relationships as being a special case. During updates we already
# have an instance pk for the relationships to be associated with. # have an instance pk for the relationships to be associated with.
m2m_fields = [] m2m_fields = []
partial_update_extra_fields = self.get_partial_update_extra_fields() partial_update_extra_fields = self.get_partial_update_extra_fields(info.fields.keys())
update_fields = [*(partial_update_extra_fields or [])] update_fields = [*(partial_update_extra_fields or [])]
for attr, value in validated_data.items(): for attr, value in validated_data.items():
if attr in info.relations and info.relations[attr].to_many: if attr in info.relations and info.relations[attr].to_many:
@ -1633,7 +1633,7 @@ class ModelSerializer(Serializer):
return validators return validators
def get_partial_update_extra_fields(self): def get_partial_update_extra_fields(self, field_names):
partial_update_extra_fields = getattr(self.Meta, 'partial_update_extra_fields', None) partial_update_extra_fields = getattr(self.Meta, 'partial_update_extra_fields', None)
if partial_update_extra_fields is not None and not isinstance(partial_update_extra_fields, (list, tuple)): if partial_update_extra_fields is not None and not isinstance(partial_update_extra_fields, (list, tuple)):
@ -1642,10 +1642,9 @@ class ModelSerializer(Serializer):
type(partial_update_extra_fields).__name__ type(partial_update_extra_fields).__name__
) )
fields = self.get_fields()
if partial_update_extra_fields is not None: if partial_update_extra_fields is not None:
for field_name in partial_update_extra_fields: for field_name in partial_update_extra_fields:
assert field_name in fields, ( assert field_name in field_names, (
"The field '{field_name}' was included on serializer " "The field '{field_name}' was included on serializer "
"{serializer_class} in the 'partial_update_extra_fields' option, but does " "{serializer_class} in the 'partial_update_extra_fields' option, but does "
"not match any model field.".format( "not match any model field.".format(

View File

@ -1301,6 +1301,11 @@ class Issue6751Model(models.Model):
char_field2 = models.CharField(max_length=100) char_field2 = models.CharField(max_length=100)
class Issue2648Model(models.Model):
char_field = models.CharField(max_length=100)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
@receiver(m2m_changed, sender=Issue6751Model.many_to_many.through) @receiver(m2m_changed, sender=Issue6751Model.many_to_many.through)
def process_issue6751model_m2m_changed(action, instance, **_): def process_issue6751model_m2m_changed(action, instance, **_):
if action == 'post_add': if action == 'post_add':
@ -1333,3 +1338,60 @@ class Issue6751Test(TestCase):
serializer.save() serializer.save()
self.assertEqual(instance.char_field, 'value changed by signal') self.assertEqual(instance.char_field, 'value changed by signal')
class Issue2648Test(TestCase):
def test_model_serializer_uses_partial_update_extra_fields_when_not_empty(self):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = Issue2648Model
partial_update_extra_fields = ('updated_at',)
fields = ('updated_at', 'char_field',)
instance = Issue2648Model.objects.create(char_field='initial value')
instance.updated_at = None
instance.save(update_fields=['updated_at'])
serializer = TestSerializer(instance=instance, data={'char_field': 'char_field updated value'}, partial=True)
serializer.is_valid()
serializer.save()
self.assertEqual(instance.char_field, 'char_field updated value')
self.assertIsNotNone(instance.updated_at)
def test_model_serializer_uses_partial_update_extra_fields_when_empty(self):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = Issue2648Model
partial_update_extra_fields = []
fields = ('updated_at', 'char_field',)
instance = Issue2648Model.objects.create(char_field='initial value')
instance.updated_at = None
instance.save(update_fields=['updated_at'])
serializer = TestSerializer(instance=instance, data={'char_field': 'char_field updated value'}, partial=True)
serializer.is_valid()
serializer.save()
self.assertEqual(instance.char_field, 'char_field updated value')
self.assertIsNone(instance.updated_at)
def test_model_serializer_validate_partial_update_extra_fields_are_model_fields(self):
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = Issue2648Model
partial_update_extra_fields = ('missing_model_field',)
fields = ('updated_at', 'char_field',)
instance = Issue2648Model.objects.create(char_field='initial value')
serializer = TestSerializer(instance=instance, data={'char_field': 'char_field updated value'}, partial=True)
serializer.is_valid()
expected = (
"The field 'missing_model_field' was included on serializer "
"TestSerializer in the 'partial_update_extra_fields' option, but does "
"not match any model field."
)
with self.assertRaisesMessage(AssertionError, expected):
serializer.save()