2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 03:00:54 +00:00

Improve StockItem API speed (#5042)

- Removes child detail fields which cannot be effectively annotated
- Prefetch required fields
- Add unit test method for checking query count
This commit is contained in:
Oliver
2023-06-14 18:33:49 +10:00
committed by GitHub
parent 8d16abcefb
commit be6ab14c9b
5 changed files with 73 additions and 11 deletions

View File

@ -795,15 +795,6 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
queryset = StockSerializers.StockItemSerializer.annotate_queryset(queryset)
# Also ensure that we pre-fecth all the related items
queryset = queryset.prefetch_related(
'part',
'part__category',
'location',
'test_results',
'tags',
)
return queryset
def filter_queryset(self, queryset):

View File

@ -231,10 +231,17 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
"""Add some extra annotations to the queryset, performing database queries as efficiently as possible."""
queryset = queryset.prefetch_related(
'location',
'sales_order',
'purchase_order',
'part',
'part__category',
'part__pricing_data',
'supplier_part',
'supplier_part__manufacturer_part',
'supplier_part__tags',
'test_results',
'tags',
)
# Annotate the queryset with the total allocated to sales orders
@ -280,7 +287,7 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
status_text = serializers.CharField(source='get_status_display', read_only=True)
# Optional detail fields, which can be appended via query parameters
supplier_part_detail = SupplierPartSerializer(source='supplier_part', many=False, read_only=True)
supplier_part_detail = SupplierPartSerializer(source='supplier_part', supplier_detail=False, manufacturer_detail=False, part_detail=False, many=False, read_only=True)
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
location_detail = LocationBriefSerializer(source='location', many=False, read_only=True)
tests = StockItemTestResultSerializer(source='test_results', many=True, read_only=True)

View File

@ -557,6 +557,42 @@ class StockItemListTest(StockAPITestCase):
self.assertEqual(len(dataset), 17)
def test_query_count(self):
"""Test that the number of queries required to fetch stock items is reasonable."""
def get_stock(data):
"""Helper function to fetch stock items."""
response = self.client.get(self.list_url, data=data)
self.assertEqual(response.status_code, 200)
return response.data
# Create a bunch of StockItem objects
prt = Part.objects.first()
StockItem.objects.bulk_create([
StockItem(
part=prt,
quantity=1,
level=0, tree_id=0, lft=0, rght=0,
) for _ in range(100)
])
# List *all* stock items
with self.assertNumQueriesLessThan(25):
get_stock({})
# List all stock items, with part detail
with self.assertNumQueriesLessThan(20):
get_stock({'part_detail': True})
# List all stock items, with supplier_part detail
with self.assertNumQueriesLessThan(20):
get_stock({'supplier_part_detail': True})
# List all stock items, with 'location' and 'tests' detail
with self.assertNumQueriesLessThan(20):
get_stock({'location_detail': True, 'tests': True})
class StockItemTest(StockAPITestCase):
"""Series of API tests for the StockItem API."""