mirror of
https://github.com/inventree/InvenTree.git
synced 2025-12-16 17:28:11 +00:00
Implement generic "ordering" by parameter
This commit is contained in:
@@ -3,7 +3,18 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import Q
|
from django.db.models import (
|
||||||
|
Case,
|
||||||
|
CharField,
|
||||||
|
Exists,
|
||||||
|
FloatField,
|
||||||
|
Model,
|
||||||
|
OuterRef,
|
||||||
|
Q,
|
||||||
|
Subquery,
|
||||||
|
Value,
|
||||||
|
When,
|
||||||
|
)
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
import InvenTree.conversion
|
import InvenTree.conversion
|
||||||
@@ -207,3 +218,81 @@ def filter_parametric_data(queryset: QuerySet, parameters: dict[str, str]) -> Qu
|
|||||||
)
|
)
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
def order_by_parameter(
|
||||||
|
queryset: QuerySet, model_type: Model, ordering: str | None
|
||||||
|
) -> QuerySet:
|
||||||
|
"""Order the provided queryset by a parameter value.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
queryset: The initial queryset to order.
|
||||||
|
model_type: The model type of the items in the queryset.
|
||||||
|
ordering: The ordering string provided by the user.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Ordered queryset.
|
||||||
|
|
||||||
|
Used to order returned parts based on their parameter values.
|
||||||
|
|
||||||
|
To order based on parameter value, supply an ordering string like:
|
||||||
|
- parameter_<x>
|
||||||
|
- -parameter_<x>
|
||||||
|
|
||||||
|
where:
|
||||||
|
- <x> is the ID of the PartParameterTemplate.
|
||||||
|
- A leading '-' indicates descending order.
|
||||||
|
"""
|
||||||
|
import common.models
|
||||||
|
|
||||||
|
if not ordering:
|
||||||
|
# No ordering provided - return the original queryset
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
result = re.match(r'^-?parameter_(\d+)$', ordering)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
# Ordering does not match the expected pattern - return the original queryset
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
template_id = result.group(1)
|
||||||
|
ascending = not ordering.startswith('-')
|
||||||
|
|
||||||
|
template_exists_filter = common.models.Parameter.objects.filter(
|
||||||
|
template__id=template_id,
|
||||||
|
model_type=ContentType.objects.get_for_model(model_type),
|
||||||
|
model_id=OuterRef('id'),
|
||||||
|
)
|
||||||
|
|
||||||
|
queryset = queryset.annotate(parameter_exists=Exists(template_exists_filter))
|
||||||
|
|
||||||
|
# Annotate the queryset with the parameter value for the provided template
|
||||||
|
queryset = queryset.annotate(
|
||||||
|
parameter_value=Case(
|
||||||
|
When(
|
||||||
|
parameter_exists=True,
|
||||||
|
then=Subquery(
|
||||||
|
template_exists_filter.values('data')[:1], output_field=CharField()
|
||||||
|
),
|
||||||
|
),
|
||||||
|
default=Value('', output_field=CharField()),
|
||||||
|
),
|
||||||
|
parameter_value_numeric=Case(
|
||||||
|
When(
|
||||||
|
parameter_exists=True,
|
||||||
|
then=Subquery(
|
||||||
|
template_exists_filter.values('data_numeric')[:1],
|
||||||
|
output_field=FloatField(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
default=Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
prefix = '' if ascending else '-'
|
||||||
|
|
||||||
|
return queryset.order_by(
|
||||||
|
'-parameter_exists',
|
||||||
|
f'{prefix}parameter_value_numeric',
|
||||||
|
f'{prefix}parameter_value',
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
"""Provides a JSON API for the Part app."""
|
"""Provides a JSON API for the Part app."""
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from django.db.models import Count, F, Q
|
from django.db.models import Count, F, Q
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -14,7 +12,6 @@ from drf_spectacular.utils import extend_schema_field
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
import part.filters
|
|
||||||
import part.tasks as part_tasks
|
import part.tasks as part_tasks
|
||||||
from data_exporter.mixins import DataExportViewMixin
|
from data_exporter.mixins import DataExportViewMixin
|
||||||
from InvenTree.api import (
|
from InvenTree.api import (
|
||||||
@@ -1088,32 +1085,10 @@ class PartList(
|
|||||||
queryset, self.request.query_params
|
queryset, self.request.query_params
|
||||||
)
|
)
|
||||||
|
|
||||||
# queryset = self.filter_parametric_data(queryset)
|
# Apply ordering based on query parameter
|
||||||
queryset = self.order_by_parameter(queryset)
|
queryset = common.filters.order_by_parameter(
|
||||||
|
queryset, Part, self.request.query_params.get('ordering', None)
|
||||||
return queryset
|
)
|
||||||
|
|
||||||
def order_by_parameter(self, queryset):
|
|
||||||
"""Perform queryset ordering based on parameter value.
|
|
||||||
|
|
||||||
- Used if the 'ordering' query param points to a parameter
|
|
||||||
- e.g. '&ordering=param_<id>' where <id> specifies the PartParameterTemplate
|
|
||||||
- Only parts which have a matching parameter are returned
|
|
||||||
- Queryset is ordered based on parameter value
|
|
||||||
"""
|
|
||||||
# Extract "ordering" parameter from query args
|
|
||||||
ordering = self.request.query_params.get('ordering', None)
|
|
||||||
|
|
||||||
if ordering:
|
|
||||||
# Ordering value must match required regex pattern
|
|
||||||
result = re.match(r'^\-?parameter_(\d+)$', ordering)
|
|
||||||
|
|
||||||
if result:
|
|
||||||
template_id = result.group(1)
|
|
||||||
ascending = not ordering.startswith('-')
|
|
||||||
queryset = part.filters.order_by_parameter(
|
|
||||||
queryset, template_id, ascending
|
|
||||||
)
|
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user