@@ -578,47 +578,14 @@ def _save_reverse_relations(self, related_objects, instance):
578578 field .save (** kwargs )
579579
580580
581- class NestedSaveListSerializer (serializers .ListSerializer ):
582- """Need a special save() method that cascades to the list of child instances"""
583-
584- def save (self , ** kwargs ):
585- """
586- Save and return a list of object instances.
587- """
588- # Guard against incorrect use of `serializer.save(commit=False)`
589- assert 'commit' not in kwargs , (
590- "'commit' is not a valid keyword argument to the 'save()' method. "
591- "If you need to access data before committing to the database then "
592- "inspect 'serializer.validated_data' instead. "
593- "You can also pass additional keyword arguments to 'save()' if you "
594- "need to set extra attributes on the saved model instance. "
595- "For example: 'serializer.save(owner=request.user)'.'"
596- )
597-
598- new_values = []
599-
600- for item in self ._validated_data :
601- # integrate save kwargs
602- self .child ._validated_data = item
603- # since we reuse the serializer, we need to re-inject the new _validated_data using save kwargs
604- new_values .append (self .child .save (** kwargs ))
605-
606- return new_values
607-
608- def run_validation (self , data = empty ):
609- """Since a nested serializer is treated like a Field, `is_valid` will not be called so we need to set
610- _validated_data in the mixin."""
611- self ._validated_data = super (NestedSaveListSerializer , self ).run_validation (data )
612- return self ._validated_data
613-
614-
615581class FocalSaveMixin (FieldLookupMixin ):
582+ """Provides a framework for extracting the values needed to get or create the focal object."""
616583
617584 @transaction .atomic
618585 def save (self , ** kwargs ):
619586 match_on = {}
620587 m2m_relations = {}
621- defaults = {}
588+ create_values = {}
622589 for field_name , field in self .fields .items ():
623590 if self .match_on == '__all__' or field_name in self .match_on :
624591 # add to match_on dict
@@ -628,40 +595,74 @@ def save(self, **kwargs):
628595 m2m_relations [field_name ] = kwargs .get (field_name , self ._validated_data .get (field_name ))
629596 elif self .field_types [field_name ] == self .TYPE_LOCAL :
630597 # need to check kwargs since there's no pre-processing
631- defaults [field_name ] = kwargs .get (field_name , self ._validated_data .get (field_name ))
598+ create_values [field_name ] = kwargs .get (field_name , self ._validated_data .get (field_name ))
632599 elif self .field_types [field_name ] == self .TYPE_DIRECT :
633600 # kwargs should have been injected when direct relations were saved
634- defaults [field_name ] = self ._validated_data .get (field_name )
601+ create_values [field_name ] = self ._validated_data .get (field_name )
635602 # make reverse relations aren't sent to a create
636603 # a parent serializer may inject a value that isn't among the fields, but is in `match_on`
637604 for key in self .match_on :
638605 if key not in self .fields .keys ():
639606 match_on [key ] = kwargs .get (key , None )
640607 try :
641- match , updated = self .do_save (match_on , defaults )
608+ match , updated = self .do_save (match_on , create_values )
642609 if not updated :
643- updated = self .do_update (match , defaults )
610+ updated = self .do_update (match , create_values )
644611 if updated :
645612 match .save ()
646613 except (TypeError , ValueError ):
647614 self .fail ('incorrect_type' , data_type = type (self ._validated_data ).__name__ )
648615 self .do_m2m_update (match , m2m_relations )
649616 return match
650617
651- def do_save (self , match_on , defaults ):
618+ def do_save (self , match_on , create_values ):
652619 """Returns the object requested by match_on and defaults."""
653620 raise NotImplementedError ("Must use a SerializerMixin or provide a save behavior." )
654621
655- def do_update (self , match , defaults ):
622+ def do_update (self , match , create_values ):
656623 """Update the match (if appropriate) and returns a boolean indicating whether or not a save is required."""
657624 return False
658625
659626 def do_m2m_update (self , match , m2m_relations ):
660627 return # no update
661628
662629
630+ class NestedSaveListSerializer (serializers .ListSerializer ):
631+ """Need a special save() method that cascades to the list of child instances"""
632+
633+ def save (self , ** kwargs ):
634+ """
635+ Save and return a list of object instances.
636+ """
637+ # Guard against incorrect use of `serializer.save(commit=False)`
638+ assert 'commit' not in kwargs , (
639+ "'commit' is not a valid keyword argument to the 'save()' method. "
640+ "If you need to access data before committing to the database then "
641+ "inspect 'serializer.validated_data' instead. "
642+ "You can also pass additional keyword arguments to 'save()' if you "
643+ "need to set extra attributes on the saved model instance. "
644+ "For example: 'serializer.save(owner=request.user)'.'"
645+ )
646+
647+ new_values = []
648+
649+ for item in self ._validated_data :
650+ # integrate save kwargs
651+ self .child ._validated_data = item
652+ # since we reuse the serializer, we need to re-inject the new _validated_data using save kwargs
653+ new_values .append (self .child .save (** kwargs ))
654+
655+ return new_values
656+
657+ def run_validation (self , data = empty ):
658+ """Since a nested serializer is treated like a Field, `is_valid` will not be called so we need to set
659+ _validated_data in the mixin."""
660+ self ._validated_data = super (NestedSaveListSerializer , self ).run_validation (data )
661+ return self ._validated_data
662+
663+
663664class NestedSaveSerializer (RelatedSaveMixin , FocalSaveMixin ):
664- """Provides a general framework for nested serializers including argument validation and common save/update behaviors """
665+ """Provides a general framework for nested serializers including argument validation. """
665666
666667 default_list_serializer = NestedSaveListSerializer
667668 DEFAULT_MATCH_ON = ['pk' ]
@@ -752,8 +753,8 @@ def create(self, validated_data):
752753
753754class UpdateDoSaveMixin (NestedSaveSerializer ):
754755
755- def do_update (self , match , defaults ):
756- for k , v in defaults .items ():
756+ def do_update (self , match , create_values ):
757+ for k , v in create_values .items ():
757758 setattr (match , k , v )
758759 return True
759760
@@ -766,7 +767,7 @@ def do_m2m_update(self, match, m2m_relations):
766767class GetOnlyNestedSerializerMixin (NestedSaveSerializer ):
767768 """Gets (without updating) requetsed object or fails."""
768769
769- def do_save (self , match_on , defaults ):
770+ def do_save (self , match_on , create_values ):
770771 return self .queryset .select_for_update ().get (** match_on ), False
771772
772773
@@ -777,11 +778,11 @@ class UpdateOnlyNestedSerializerMixin(UpdateDoSaveMixin, GetOnlyNestedSerializer
777778class GetOrCreateNestedSerializerMixin (GetOnlyNestedSerializerMixin ):
778779 """Gets (without updating) or creates requested object."""
779780
780- def do_save (self , match_on , defaults ):
781+ def do_save (self , match_on , create_values ):
781782 try :
782- return super (GetOrCreateNestedSerializerMixin , self ).do_save (match_on , defaults )
783+ return super (GetOrCreateNestedSerializerMixin , self ).do_save (match_on , create_values )
783784 except self .queryset .model .DoesNotExist :
784- return self .queryset .model (** defaults ), True
785+ return self .queryset .model (** create_values ), True
785786
786787
787788class UpdateOrCreateNestedSerializerMixin (UpdateDoSaveMixin , GetOrCreateNestedSerializerMixin ):
@@ -791,5 +792,5 @@ class UpdateOrCreateNestedSerializerMixin(UpdateDoSaveMixin, GetOrCreateNestedSe
791792class CreateOnlyNestedSerializerMixin (NestedSaveSerializer ):
792793 """Creates requested object or fails."""
793794
794- def do_save (self , match_on , defaults ):
795- return self .queryset .model (** defaults ), True
795+ def do_save (self , match_on , create_values ):
796+ return self .queryset .model (** create_values ), True
0 commit comments