-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[refactor] Optional prefetch #11012
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
[refactor] Optional prefetch #11012
Conversation
- Allows us to *not* prefetch fields (expensive) when they are not going to be used - Enables re-usable components for common detail fields
- Automatically apply correct prefetch fields
- add 'enable_parameters_filter' function - Prefetch parameters only when needed - Refactor / consolidate code
- Make fields switchable - Ensure correct prefetch_related
✅ Deploy Preview for inventree-web-pui-preview canceled.
|
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.
Pull request overview
This PR introduces conditional prefetching for filterable serializer fields to optimize database queries by only prefetching relationships when their corresponding fields are actually included in the API response.
Key Changes:
- Added
prefetch_fieldsandprefetch_funcparameters to theenable_filterdecorator to specify relationships that should be prefetched when a field is included - Implemented automatic prefetching in
FilterableSerializerMixin.prefetch_queryset()method that collects and applies prefetch directives from enabled fields - Created reusable filter helper functions (
enable_project_code_filter,enable_project_label_filter,enable_parameters_filter) incommon.filtersto standardize common patterns
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
InvenTree/serializers.py |
Added prefetch infrastructure to FilterableSerializerField and enable_filter decorator; implemented prefetch_queryset method in FilterableSerializerMixin |
InvenTree/mixins.py |
Modified OutputOptionsMixin.get_queryset() to automatically apply prefetching based on included filterable fields |
InvenTree/models.py |
Added prefetch for parameters_list__updated_by in annotate_parameters method |
common/filters.py |
Added three helper functions for common filterable field patterns (project_code, project_label, parameters) with appropriate prefetch configurations |
part/serializers.py |
Removed static parameter annotation; replaced manual parameters field with enable_parameters_filter() helper |
order/serializers.py |
Replaced manual field definitions with filter helpers; added prefetch_fields to contact, responsible, address, supplier, and customer detail fields; removed static parameter annotations |
company/serializers.py |
Replaced manual field definitions with filter helpers; wrapped part_detail, supplier_detail, manufacturer_detail, and manufacturer_part_detail with enable_filter including prefetch_fields |
build/serializers.py |
Replaced manual field definitions with filter helpers; added prefetch_fields to part_detail, issued_by, and responsible_detail fields; removed static parameter annotation |
order/api.py |
Removed manual prefetch_related calls for responsible, project_code, and lines (now handled by conditional prefetching) |
company/api.py |
Removed manual prefetch_related calls for part and manufacturer (now handled by conditional prefetching) |
build/api.py |
Removed manual prefetch_related calls for responsible, issued_by, build_lines, part, and project_code (now handled by conditional prefetching) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
matmair
left a comment
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.
Looks like a good improvement, using common filters is great;
I am not sure if we even need the provided flexibility for the common filters; did you have something specific in mind when providing it? Having these things static might promote a more uniform API
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #11012 +/- ##
==========================================
- Coverage 88.16% 88.16% -0.01%
==========================================
Files 1290 1290
Lines 58039 58074 +35
Branches 1970 1970
==========================================
+ Hits 51172 51201 +29
- Misses 6376 6382 +6
Partials 491 491
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
| def test_filterable_fields(self): | ||
| """Test inclusion/exclusion of optional API fields.""" | ||
| fields = { |
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.
@SchrodingersGat you could also use the run_output_test helper for this
| filterable_fields = [ | ||
| field | ||
| for field in self.fields.values() | ||
| if getattr(field, 'is_filterable', None) | ||
| ] | ||
|
|
||
| for field in filterable_fields: |
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.
The serializer already contains filter_targets, that gets build by the gather_filters function. Could we use that here instead of iterating over all fields again?
- Prefetch roles - Prevents significant number of db hits
…e into filter-prefetch
- Improved prefetching
- Off by default - Only prefetch when requested (expensive) - Ref: inventree#11012 - Ref: inventree#11002 - Closes inventree#10996
- Specify prefetch_fields for optional child serializers - Ref: inventree#11012
* API refactoring - Specify prefetch_fields for optional child serializers - Ref: #11012 * Fixes for unit tests
Problem Description
We have multiple places in the code where we call
enable_filter- to dynamically add (or remove) nested related fields from an API serializer.To prevent 1 + N database fetches, we must call
prefetch_relatedon all fields which are to be included - even if they are not included. So, potentially we are prefetching querysets which never even get used.This is a problem as there is a non-zero cost associated with prefetching - see #10996
Ideally, we should only prefetch related fields when they are actually needed - that way we do not pay the price of prefetching when it is not needed
Solution
This PR adds the option to specify a list of prefetch fields to the
enable_filterhook.This PR introduces the new functionality, but does not refactor all instances, to reduce scope.
Performance Comparison
/api/part/?limit=500/api/part/?limit=500¶meters=0/api/part/?limit=500¶meters=1/api/company/?limit=500/api/company/?limit=500¶meters=0/api/company/?limit=500¶meters=1Follow-up PRs
enable_filtercalls