-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
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
Conversation
Not looked into this in any detail, but the tests are failing against hyperlinked relationships. Which can also use the pk only optimisation... https://github.com/orf/django-rest-framework/blob/1d990eaba10d542978cbf35d57497858e6f0c3a7/rest_framework/relations.py#L284 |
I removed that check and added an |
for item in data | ||
] | ||
if isinstance(self.child_relation, PrimaryKeyRelatedField): | ||
values = list(self.child_relation.get_queryset().filter(pk__in=data)) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
] | ||
if isinstance(self.child_relation, PrimaryKeyRelatedField): | ||
values = list(self.child_relation.get_queryset().filter(pk__in=data)) | ||
missing_primary_keys = set(v.pk for v in values) - set(data) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea here but not that it just solves the issue for PrimaryKeyRelatedField
.
The if isinstance(self.child_relation, PrimaryKeyRelatedField)
special case looks to me like it's queuing up work for later.
to_internal_value
is performing two tasks: mapping from the wire representation to lookup parameters and the lookup itself.
In the many
case the lookup is always an __in
on whatever the lookup field was, so it should be pretty generic.
Even HyperlinkRelatedField
has two clearly separate phases: the Map and the lookup
If these were separately callableManyRelatedField
should be able to build the lookup (for each RelatedField
subclass) for a single fetch, as per the intention.
I agree that it's a special case @carltongibson, but doing anything else would be a major breaking change. Third party fields would rely on Perhaps we could add another method that converts from the wire API and returns something we can use as a filter (perhaps a Q object would be best?) and have the base Again, queuing up work isn't a bad thing unless nobody wants to do the work. This MR doesn't solve it for the general case, but it solves it for And its backwards compatible 👍 |
@orf I'm not suggesting we break If it were refactored to look a bit like this:
... then |
oh right, so perhaps a |
Closing as a known limitation in line with #5150. (Full featured PRs welcomed.) |
Re: #4917
Lets see if the tests pass.