Skip to content

Commit

Permalink
🐛Fix operation related bug on nested fields
Browse files Browse the repository at this point in the history
  • Loading branch information
yezyilomo committed Jan 25, 2024
1 parent 05b2140 commit e7e6563
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 16 deletions.
24 changes: 17 additions & 7 deletions django_restql/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def run_pk_list_validation(self, pks):
many=True
).run_validation(pks)

def run_data_list_validation(self, data, partial=None):
def run_data_list_validation(self, data, partial=None, operation=None):
ListField().run_validation(data)
model = self.parent.Meta.model
rel = getattr(model, self.source).rel
Expand All @@ -143,7 +143,7 @@ def run_data_list_validation(self, data, partial=None):
data=data,
many=True,
partial=partial,
context=self.context
context={**self.context, "parent_operation": operation}
)

# Remove parent field(field_name) for validation purpose
Expand All @@ -158,7 +158,7 @@ def run_data_list_validation(self, data, partial=None):
data=data,
many=True,
partial=partial,
context=self.context
context={**self.context, "parent_operation": operation}
)

# Check if a serializer is valid
Expand All @@ -170,7 +170,8 @@ def run_add_list_validation(self, data):
def run_create_list_validation(self, data):
self.run_data_list_validation(
data,
partial=self.is_partial(False)
partial=self.is_partial(False),
operation=CREATE
)

def run_remove_list_validation(self, data):
Expand All @@ -191,7 +192,8 @@ def run_update_list_validation(self, data):
values = list(data.values())
self.run_data_list_validation(
values,
partial=self.is_partial(True)
partial=self.is_partial(True),
operation=UPDATE
)

def run_data_validation(self, data, allowed_ops):
Expand Down Expand Up @@ -227,8 +229,14 @@ def run_data_validation(self, data, allowed_ops):

def to_internal_value(self, data):
if self.child.root.instance is None:
self.run_data_validation(data, create_ops)
parent_operation = self.context.get("parent_operation")
if parent_operation == "update":
# Definitely an update
self.run_data_validation(data, update_ops)
else:
self.run_data_validation(data, create_ops)
else:
# Definitely an update
self.run_data_validation(data, update_ops)
return data

Expand Down Expand Up @@ -266,13 +274,15 @@ def run_pk_validation(self, pk):
return validator.run_validation(pk)

def run_data_validation(self, data):
parent_operation = self.context.get("parent_operation")

child_serializer = serializer_class(
**self.validation_kwargs,
data=data,
partial=self.is_partial(
# Use the partial value passed, if it's not passed
# Use the one from the top level parent
self.root.partial
True if parent_operation == UPDATE else False
),
context=self.context
)
Expand Down
27 changes: 18 additions & 9 deletions django_restql/mixins.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.db.models import Prefetch
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.fields.related import ManyToManyRel, ManyToOneRel
from django.http import QueryDict
from django.utils.functional import cached_property
Expand Down Expand Up @@ -597,7 +598,7 @@ def create_writable_foreignkey_related(self, data):
# Reject partial update by default(if partial kwarg is not passed)
# since we need all required fields when creating object
partial=nested_field_serializer.is_partial(False),
context=self.context
context={**self.context, "parent_operation": CREATE}
)
serializer.is_valid(raise_exception=True)
if value is None:
Expand All @@ -622,7 +623,7 @@ def bulk_create_objs(self, field, data):
# Reject partial update by default(if partial kwarg is not passed)
# since we need all required fields when creating object
partial=nested_field_serializer.is_partial(False),
context=self.context,
context={**self.context, "parent_operation": CREATE},
)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
Expand Down Expand Up @@ -770,7 +771,7 @@ def update_writable_foreignkey_related(self, instance, data):
# Allow partial update by default(if partial kwarg is not passed)
# since this is nested update
partial=nested_field_serializer.is_partial(True),
context=self.context
context={**self.context, "parent_operation": UPDATE}
)
serializer.is_valid(raise_exception=True)
if values is None:
Expand Down Expand Up @@ -798,7 +799,7 @@ def bulk_create_many_to_many_related(self, field, nested_obj, data):
# Reject partial update by default(if partial kwarg is not passed)
# since we need all required fields when creating object
partial=nested_field_serializer.is_partial(False),
context=self.context
context={**self.context, "parent_operation": CREATE}
)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
Expand All @@ -819,7 +820,7 @@ def bulk_create_many_to_one_related(self, field, nested_obj, data):
# Reject partial update by default(if partial kwarg is not passed)
# since we need all required fields when creating object
partial=nested_field_serializer.is_partial(False),
context=self.context
context={**self.context, "parent_operation": CREATE}
)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
Expand All @@ -834,15 +835,19 @@ def bulk_update_many_to_many_related(self, field, nested_obj, data):
serializer_class = nested_field_serializer.serializer_class
kwargs = nested_field_serializer.validation_kwargs
for pk, values in data.items():
obj = nested_obj.get(pk=pk)
try:
obj = nested_obj.get(pk=pk)
except ObjectDoesNotExist:
# This pk does't belong to nested field
continue
serializer = serializer_class(
obj,
**kwargs,
data=values,
# Allow partial update by default(if partial kwarg is not passed)
# since this is nested update
partial=nested_field_serializer.is_partial(True),
context=self.context
context={**self.context, "parent_operation": UPDATE}
)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
Expand All @@ -858,7 +863,11 @@ def bulk_update_many_to_one_related(self, field, instance, data):
foreignkey = getattr(model, field).field.name
nested_obj = getattr(instance, field)
for pk, values in data.items():
obj = nested_obj.get(pk=pk)
try:
obj = nested_obj.get(pk=pk)
except ObjectDoesNotExist:
# This pk does't belong to nested field
continue
values.update({foreignkey: instance.pk})
serializer = serializer_class(
obj,
Expand All @@ -867,7 +876,7 @@ def bulk_update_many_to_one_related(self, field, instance, data):
# Allow partial update by default(if partial kwarg is not passed)
# since this is nested update
partial=nested_field_serializer.is_partial(True),
context=self.context
context={**self.context, "parent_operation": UPDATE}
)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
Expand Down

0 comments on commit e7e6563

Please sign in to comment.