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

#4917 - Remove O(n) queries in m2m updates #5093

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions rest_framework/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,10 +492,19 @@ def to_internal_value(self, data):
if not self.allow_empty and len(data) == 0:
self.fail('empty')

return [
self.child_relation.to_internal_value(item)
for item in data
]
if isinstance(self.child_relation, PrimaryKeyRelatedField):
values = list(self.child_relation.get_queryset().filter(pk__in=data))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not use values_list('pk', flat=True) here to just fetch the ids and skip object instantiation?

Copy link
Contributor Author

@orf orf Apr 25, 2017

Choose a reason for hiding this comment

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

Because we then return the values below (line 507), which need to be full model instances.

missing_primary_keys = set(v.pk for v in values) - set(data)
Copy link

@EmreSoner EmreSoner Apr 25, 2017

Choose a reason for hiding this comment

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

If you use set for unique list, why not use distinct on values filter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We are not bothered about distinct values, Model.objects.filter(pk__in=[1, 1]) will only return 1 model AFAIK. We use set() here to just easily find any differences between the returned list of primary keys and the given list of primary keys.


if missing_primary_keys:
self.fail('missing_ids', ids_not_found=list(missing_primary_keys))
else:
values = [
self.child_relation.to_internal_value(item)
for item in data
]

return values

def get_attribute(self, instance):
# Can't have any relationships if not created
Expand Down