2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-05-13 10:33:07 +00:00
Oliver 175d9555b0
Tree query improvements (#3443)
* Allow part category table to be ordered by part count

* Add queryset annotation for part-category part-count

- Uses subquery to annotate the part-count for sub-categories
- Huge reduction in number of queries

* Update 'pathstring' property of PartCategory and StockLocation

- No longer a dynamically calculated value
- Constructed when the model is saved, and then written to the database
- Limited to 250 characters

* Data migration to re-construct pathstring for PartCategory objects

* Fix for tree model save() method

* Add unit tests for pathstring construction

* Data migration for StockLocation pathstring values

* Update part API

- Add new annotation to PartLocationDetail view

* Update API version

* Apply similar annotation to StockLocation API endpoints

* Extra tests for PartCategory API

* Unit test fixes

* Allow PartCategory and StockLocation lists to be sorted by 'pathstring'

* Further unit test fixes
2022-08-01 13:43:27 +10:00

37 lines
1.1 KiB
Python

"""Custom query filters for the Stock models"""
from django.db.models import F, Func, IntegerField, OuterRef, Q, Subquery
from django.db.models.functions import Coalesce
import stock.models
def annotate_location_items(filter: Q = None):
"""Construct a queryset annotation which returns the number of stock items in a particular location.
- Includes items in subcategories also
- Requires subquery to perform annotation
"""
# Construct a subquery to provide all items in this location and any sublocations
subquery = stock.models.StockItem.objects.exclude(location=None).filter(
location__tree_id=OuterRef('tree_id'),
location__lft__gte=OuterRef('lft'),
location__rght__lte=OuterRef('rght'),
location__level__gte=OuterRef('level'),
)
# Optionally apply extra filter to returned results
if filter is not None:
subquery = subquery.filter(filter)
return Coalesce(
Subquery(
subquery.annotate(
total=Func(F('pk'), function='COUNT', output_field=IntegerField())
).values('total')
),
0,
output_field=IntegerField()
)