mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-01 03:00:54 +00:00
Fix: Treegrid is loading an eternity for huge amounts of data (#3451)
* Added default max depth and lazy loading to StorageLocation * Added default max depth and lazy loading to PartCategory * Update API version * lint: fix * Added INVENTREE_TREE_DEPTH setting * Refactored int conversion into own helper function * Added tests
This commit is contained in:
@ -26,7 +26,7 @@ from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
|
||||
ListCreateDestroyAPIView)
|
||||
from InvenTree.filters import InvenTreeOrderingFilter
|
||||
from InvenTree.helpers import (DownloadFile, extract_serial_numbers, isNull,
|
||||
str2bool)
|
||||
str2bool, str2int)
|
||||
from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI, RetrieveAPI,
|
||||
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI)
|
||||
from order.models import PurchaseOrder, SalesOrder, SalesOrderAllocation
|
||||
@ -241,6 +241,8 @@ class StockLocationList(ListCreateAPI):
|
||||
|
||||
cascade = str2bool(params.get('cascade', False))
|
||||
|
||||
depth = str2int(params.get('depth', None))
|
||||
|
||||
# Do not filter by location
|
||||
if loc_id is None:
|
||||
pass
|
||||
@ -251,6 +253,9 @@ class StockLocationList(ListCreateAPI):
|
||||
if not cascade:
|
||||
queryset = queryset.filter(parent=None)
|
||||
|
||||
if cascade and depth is not None:
|
||||
queryset = queryset.filter(level__lte=depth)
|
||||
|
||||
else:
|
||||
|
||||
try:
|
||||
@ -259,6 +264,9 @@ class StockLocationList(ListCreateAPI):
|
||||
# All sub-locations to be returned too?
|
||||
if cascade:
|
||||
parents = location.get_descendants(include_self=True)
|
||||
if depth is not None:
|
||||
parents = parents.filter(level__lte=location.level + depth)
|
||||
|
||||
parent_ids = [p.id for p in parents]
|
||||
queryset = queryset.filter(parent__in=parent_ids)
|
||||
|
||||
|
@ -54,11 +54,44 @@ class StockLocationTest(StockAPITestCase):
|
||||
StockLocation.objects.create(name='top', description='top category')
|
||||
|
||||
def test_list(self):
|
||||
"""Test StockLocation list."""
|
||||
# Check that we can request the StockLocation list
|
||||
response = self.client.get(self.list_url, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertGreaterEqual(len(response.data), 1)
|
||||
"""Test the StockLocationList API endpoint"""
|
||||
test_cases = [
|
||||
({}, 8, 'no parameters'),
|
||||
({'parent': 1, 'cascade': False}, 2, 'Filter by parent, no cascading'),
|
||||
({'parent': 1, 'cascade': True}, 2, 'Filter by parent, cascading'),
|
||||
({'cascade': True, 'depth': 0}, 8, 'Cascade with no parent, depth=0'),
|
||||
({'cascade': False, 'depth': 10}, 8, 'Cascade with no parent, depth=0'),
|
||||
({'parent': 'null', 'cascade': True, 'depth': 0}, 7, 'Cascade with null parent, depth=0'),
|
||||
({'parent': 'null', 'cascade': True, 'depth': 10}, 8, 'Cascade with null parent and bigger depth'),
|
||||
({'parent': 'null', 'cascade': False, 'depth': 10}, 3, 'No cascade even with depth specified with null parent'),
|
||||
({'parent': 1, 'cascade': False, 'depth': 0}, 2, 'Dont cascade with depth=0 and parent'),
|
||||
({'parent': 1, 'cascade': True, 'depth': 0}, 2, 'Cascade with depth=0 and parent'),
|
||||
({'parent': 1, 'cascade': False, 'depth': 1}, 2, 'Dont cascade even with depth=1 specified with parent'),
|
||||
({'parent': 1, 'cascade': True, 'depth': 1}, 2, 'Cascade with depth=1 with parent'),
|
||||
({'parent': 1, 'cascade': True, 'depth': 'abcdefg'}, 2, 'Cascade with invalid depth and parent'),
|
||||
]
|
||||
|
||||
for params, res_len, description in test_cases:
|
||||
response = self.get(self.list_url, params, expected_code=200)
|
||||
self.assertEqual(len(response.data), res_len, description)
|
||||
|
||||
# Check that the required fields are present
|
||||
fields = [
|
||||
'pk',
|
||||
'name',
|
||||
'description',
|
||||
'level',
|
||||
'parent',
|
||||
'items',
|
||||
'pathstring',
|
||||
'owner',
|
||||
'url'
|
||||
]
|
||||
|
||||
response = self.get(self.list_url, expected_code=200)
|
||||
for result in response.data:
|
||||
for f in fields:
|
||||
self.assertIn(f, result)
|
||||
|
||||
def test_add(self):
|
||||
"""Test adding StockLocation."""
|
||||
|
Reference in New Issue
Block a user