Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ListSerializer #9244

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 32 additions & 13 deletions rest_framework/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

from rest_framework.compat import postgres_fields
from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.fields import get_error_detail
from rest_framework.fields import get_attribute, get_error_detail
from rest_framework.settings import api_settings
from rest_framework.utils import html, model_meta, representation
from rest_framework.utils.field_mapping import (
Expand Down Expand Up @@ -610,11 +610,6 @@ def __init__(self, *args, **kwargs):
assert self.child is not None, '`child` is a required argument.'
assert not inspect.isclass(self.child), '`child` has not been instantiated.'

instance = kwargs.get('instance', [])
data = kwargs.get('data', [])
if instance and data:
assert len(data) == len(instance), 'Data and instance should have same length'

super().__init__(*args, **kwargs)
self.child.bind(field_name='', parent=self)

Expand Down Expand Up @@ -700,13 +695,37 @@ def to_internal_value(self, data):
ret = []
errors = []

for idx, item in enumerate(data):
if (
hasattr(self, 'instance')
and self.instance
and len(self.instance) > idx
):
self.child.instance = self.instance[idx]
if not self.instance and self.parent and self.parent.instance:
rel_mgr = get_attribute(self.parent.instance, self.source_attrs)
self.instance = rel_mgr.all() if rel_mgr else None
Comment on lines +698 to +700
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is the best place to do this. I'd like to hear the opinion of someone more familiar with this codebase.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you give a more verbose name to rel_mgr please? also share a bit more of what this would be doing?


pk_field_name = next(
field_name
for field_name, field in self.child.fields.items()
if field.source == self.child.Meta.model._meta.pk.attname
)

item_instance_dict = {}
if self.instance:
item_pks = []

for item in data:
item_pk = item.get(pk_field_name)
if item_pk:
item_pks.append(item_pk)

for item_instance in self.instance.filter(pk__in=item_pks):
item_instance_dict[item_instance.pk] = item_instance

for item in data:
self.child.initial_data = item

if self.instance:
item_pk = item.get(pk_field_name)
self.child.instance = (
item_instance_dict.get(item_pk) if item_pk else None
)

try:
validated = self.run_child_validation(item)
except ValidationError as exc:
Expand Down