Skip to content

Commit c411a9a

Browse files
committed
move save mixins near one another and improve arg names
1 parent 1d9ba6c commit c411a9a

1 file changed

Lines changed: 51 additions & 50 deletions

File tree

drf_writable_nested/mixins.py

Lines changed: 51 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
615581
class 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+
663664
class 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

753754
class 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):
766767
class 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
777778
class 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

787788
class UpdateOrCreateNestedSerializerMixin(UpdateDoSaveMixin, GetOrCreateNestedSerializerMixin):
@@ -791,5 +792,5 @@ class UpdateOrCreateNestedSerializerMixin(UpdateDoSaveMixin, GetOrCreateNestedSe
791792
class 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

Comments
 (0)