Skip to content

Commit dea601d

Browse files
authored
Merge pull request #4222 from NewVadim/master
Fix partial update for the ListSerializer.
2 parents d2d0a06 + c752e96 commit dea601d

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed

rest_framework/serializers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,10 @@ def __init__(self, *args, **kwargs):
565565
super(ListSerializer, self).__init__(*args, **kwargs)
566566
self.child.bind(field_name='', parent=self)
567567

568+
def bind(self, field_name, parent):
569+
super(ListSerializer, self).bind(field_name, parent)
570+
self.partial = self.parent.partial
571+
568572
def get_initial(self):
569573
if hasattr(self, 'initial_data'):
570574
return self.to_representation(self.initial_data)
@@ -616,6 +620,9 @@ def to_internal_value(self, data):
616620
}, code='not_a_list')
617621

618622
if not self.allow_empty and len(data) == 0:
623+
if self.parent and self.partial:
624+
raise SkipField()
625+
619626
message = self.error_messages['empty']
620627
raise ValidationError({
621628
api_settings.NON_FIELD_ERRORS_KEY: [message]

tests/test_serializer_lists.py

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,217 @@ class MultipleChoiceSerializer(serializers.Serializer):
318318
assert serializer.is_valid()
319319
assert serializer.validated_data == {}
320320
assert serializer.errors == {}
321+
322+
def test_allow_empty_true(self):
323+
class ListSerializer(serializers.Serializer):
324+
update_field = serializers.IntegerField()
325+
store_field = serializers.IntegerField()
326+
327+
instance = [
328+
{'update_field': 11, 'store_field': 12},
329+
{'update_field': 21, 'store_field': 22},
330+
]
331+
332+
serializer = ListSerializer(instance, data=[], partial=True, many=True)
333+
assert serializer.is_valid()
334+
assert serializer.validated_data == []
335+
assert serializer.errors == []
336+
337+
def test_update_allow_empty_true(self):
338+
class ListSerializer(serializers.Serializer):
339+
update_field = serializers.IntegerField()
340+
store_field = serializers.IntegerField()
341+
342+
instance = [
343+
{'update_field': 11, 'store_field': 12},
344+
{'update_field': 21, 'store_field': 22},
345+
]
346+
input_data = [{'update_field': 31}, {'update_field': 41}]
347+
updated_data_list = [
348+
{'update_field': 31, 'store_field': 12},
349+
{'update_field': 41, 'store_field': 22},
350+
]
351+
352+
serializer = ListSerializer(
353+
instance, data=input_data, partial=True, many=True)
354+
assert serializer.is_valid()
355+
356+
for index, data in enumerate(serializer.validated_data):
357+
for key, value in data.items():
358+
assert value == updated_data_list[index][key]
359+
360+
assert serializer.errors == []
361+
362+
def test_allow_empty_false(self):
363+
class ListSerializer(serializers.Serializer):
364+
update_field = serializers.IntegerField()
365+
store_field = serializers.IntegerField()
366+
367+
instance = [
368+
{'update_field': 11, 'store_field': 12},
369+
{'update_field': 21, 'store_field': 22},
370+
]
371+
372+
serializer = ListSerializer(
373+
instance, data=[], allow_empty=False, partial=True, many=True)
374+
assert not serializer.is_valid()
375+
assert serializer.validated_data == []
376+
assert len(serializer.errors) == 1
377+
assert serializer.errors['non_field_errors'][0] == 'This list may not be empty.'
378+
379+
def test_update_allow_empty_false(self):
380+
class ListSerializer(serializers.Serializer):
381+
update_field = serializers.IntegerField()
382+
store_field = serializers.IntegerField()
383+
384+
instance = [
385+
{'update_field': 11, 'store_field': 12},
386+
{'update_field': 21, 'store_field': 22},
387+
]
388+
input_data = [{'update_field': 31}, {'update_field': 41}]
389+
updated_data_list = [
390+
{'update_field': 31, 'store_field': 12},
391+
{'update_field': 41, 'store_field': 22},
392+
]
393+
394+
serializer = ListSerializer(
395+
instance, data=input_data, allow_empty=False, partial=True, many=True)
396+
assert serializer.is_valid()
397+
398+
for index, data in enumerate(serializer.validated_data):
399+
for key, value in data.items():
400+
assert value == updated_data_list[index][key]
401+
402+
assert serializer.errors == []
403+
404+
def test_as_field_allow_empty_true(self):
405+
class ListSerializer(serializers.Serializer):
406+
update_field = serializers.IntegerField()
407+
store_field = serializers.IntegerField()
408+
409+
class Serializer(serializers.Serializer):
410+
extra_field = serializers.IntegerField()
411+
list_field = ListSerializer(many=True)
412+
413+
instance = {
414+
'extra_field': 1,
415+
'list_field': [
416+
{'update_field': 11, 'store_field': 12},
417+
{'update_field': 21, 'store_field': 22},
418+
]
419+
}
420+
421+
serializer = Serializer(instance, data={}, partial=True)
422+
assert serializer.is_valid()
423+
assert serializer.validated_data == {}
424+
assert serializer.errors == {}
425+
426+
def test_udate_as_field_allow_empty_true(self):
427+
class ListSerializer(serializers.Serializer):
428+
update_field = serializers.IntegerField()
429+
store_field = serializers.IntegerField()
430+
431+
class Serializer(serializers.Serializer):
432+
extra_field = serializers.IntegerField()
433+
list_field = ListSerializer(many=True)
434+
435+
instance = {
436+
'extra_field': 1,
437+
'list_field': [
438+
{'update_field': 11, 'store_field': 12},
439+
{'update_field': 21, 'store_field': 22},
440+
]
441+
}
442+
input_data_1 = {'extra_field': 2}
443+
input_data_2 = {
444+
'list_field': [
445+
{'update_field': 31},
446+
{'update_field': 41},
447+
]
448+
}
449+
450+
# data_1
451+
serializer = Serializer(instance, data=input_data_1, partial=True)
452+
assert serializer.is_valid()
453+
assert len(serializer.validated_data) == 1
454+
assert serializer.validated_data['extra_field'] == 2
455+
assert serializer.errors == {}
456+
457+
# data_2
458+
serializer = Serializer(instance, data=input_data_2, partial=True)
459+
assert serializer.is_valid()
460+
461+
updated_data_list = [
462+
{'update_field': 31, 'store_field': 12},
463+
{'update_field': 41, 'store_field': 22},
464+
]
465+
for index, data in enumerate(serializer.validated_data['list_field']):
466+
for key, value in data.items():
467+
assert value == updated_data_list[index][key]
468+
469+
assert serializer.errors == {}
470+
471+
def test_as_field_allow_empty_false(self):
472+
class ListSerializer(serializers.Serializer):
473+
update_field = serializers.IntegerField()
474+
store_field = serializers.IntegerField()
475+
476+
class Serializer(serializers.Serializer):
477+
extra_field = serializers.IntegerField()
478+
list_field = ListSerializer(many=True, allow_empty=False)
479+
480+
instance = {
481+
'extra_field': 1,
482+
'list_field': [
483+
{'update_field': 11, 'store_field': 12},
484+
{'update_field': 21, 'store_field': 22},
485+
]
486+
}
487+
488+
serializer = Serializer(instance, data={}, partial=True)
489+
assert serializer.is_valid()
490+
assert serializer.validated_data == {}
491+
assert serializer.errors == {}
492+
493+
def test_update_as_field_allow_empty_false(self):
494+
class ListSerializer(serializers.Serializer):
495+
update_field = serializers.IntegerField()
496+
store_field = serializers.IntegerField()
497+
498+
class Serializer(serializers.Serializer):
499+
extra_field = serializers.IntegerField()
500+
list_field = ListSerializer(many=True, allow_empty=False)
501+
502+
instance = {
503+
'extra_field': 1,
504+
'list_field': [
505+
{'update_field': 11, 'store_field': 12},
506+
{'update_field': 21, 'store_field': 22},
507+
]
508+
}
509+
input_data_1 = {'extra_field': 2}
510+
input_data_2 = {
511+
'list_field': [
512+
{'update_field': 31},
513+
{'update_field': 41},
514+
]
515+
}
516+
updated_data_list = [
517+
{'update_field': 31, 'store_field': 12},
518+
{'update_field': 41, 'store_field': 22},
519+
]
520+
521+
# data_1
522+
serializer = Serializer(instance, data=input_data_1, partial=True)
523+
assert serializer.is_valid()
524+
assert serializer.errors == {}
525+
526+
# data_2
527+
serializer = Serializer(instance, data=input_data_2, partial=True)
528+
assert serializer.is_valid()
529+
530+
for index, data in enumerate(serializer.validated_data['list_field']):
531+
for key, value in data.items():
532+
assert value == updated_data_list[index][key]
533+
534+
assert serializer.errors == {}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy