From 47892e409e833907b439b0969c0bf873c8976795 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 5 Oct 2025 21:34:30 +0200 Subject: [PATCH] fix def --- src/backend/InvenTree/InvenTree/mixins.py | 2 + .../InvenTree/InvenTree/serializers.py | 59 +++++++++++++++---- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/backend/InvenTree/InvenTree/mixins.py b/src/backend/InvenTree/InvenTree/mixins.py index d5512cabc0..99b5ae2f81 100644 --- a/src/backend/InvenTree/InvenTree/mixins.py +++ b/src/backend/InvenTree/InvenTree/mixins.py @@ -14,6 +14,7 @@ from InvenTree.helpers import ( strip_html_tags, ) from InvenTree.schema import schema_for_view_output_options +from InvenTree.serializers import OptionalFilterabelSerializer class CleanMixin: @@ -203,6 +204,7 @@ class UpdateAPI(CleanMixin, generics.UpdateAPIView): class DataImportExportSerializerMixin( + OptionalFilterabelSerializer, data_exporter.mixins.DataExportSerializerMixin, importer.mixins.DataImportSerializerMixin, ): diff --git a/src/backend/InvenTree/InvenTree/serializers.py b/src/backend/InvenTree/InvenTree/serializers.py index c2fd006c78..647edcbf98 100644 --- a/src/backend/InvenTree/InvenTree/serializers.py +++ b/src/backend/InvenTree/InvenTree/serializers.py @@ -29,7 +29,7 @@ from InvenTree.fields import InvenTreeRestURLField, InvenTreeURLField # region path filtering -class OptionalFilterabelSerializer(serializers.Serializer): +class OptionalFilterabelSerializer: """Mixin to add context to serializer.""" is_filterable = None @@ -37,28 +37,53 @@ class OptionalFilterabelSerializer(serializers.Serializer): def __init__(self, *args, **kwargs): """Initialize the serializer.""" - self.is_filterable = kwargs.pop('is_filterable', None) - self.is_filterable_default = kwargs.pop('is_filterable_default', True) + if self.is_filterable is None: + self.is_filterable = kwargs.pop('is_filterable', None) + self.is_filterable_default = kwargs.pop('is_filterable_default', True) super().__init__(*args, **kwargs) -class PathScopedMixin: +class FractionalFilterabelSerializer: + """A.""" + + def __init__(self, *args, **kwargs): + """Add detail fields.""" + kwargs = PathScopedMixin.gather_filters(self, kwargs) + super().__init__(*args, **kwargs) + PathScopedMixin.do_filtering(self, *args, **kwargs) + + +class PathScopedMixin(serializers.Serializer): """Mixin to disable a serializer field based on kwargs passed to the view.""" + no_filter = False + _was_filtered = False + def __init__(self, *args, **kwargs): """Initialization routine for the serializer.""" - flt_fld = { - k: a for k, a in self.fields.items() if getattr(a, 'is_filterable', None) - } - filter_targets = {k: kwargs.pop(k, False) for k in flt_fld} - + self.gather_filters(kwargs) super().__init__(*args, **kwargs) + self.do_filtering(*args, **kwargs) - if InvenTree.ready.isGeneratingSchema(): + def gather_filters(self, kwargs): + """Gather filterable fields.""" + if getattr(self, '_was_filtered', False): + return kwargs + self._was_filtered = True + + # Actually gather the filterable fields + fields = self.fields.items() + flt_fld = {k: a for k, a in fields if getattr(a, 'is_filterable', None)} + self.filter_targets = {k: kwargs.pop(k, False) for k in flt_fld} + return kwargs + + def do_filtering(self, *args, **kwargs): + """Do the actual filtering.""" + if InvenTree.ready.isGeneratingSchema() or not hasattr(self, 'filter_targets'): return # Throw out fields which are not requested - for k, v in filter_targets.items(): + for k, v in self.filter_targets.items(): if v is not True: self.fields.pop(k, None) @@ -66,6 +91,14 @@ class PathScopedMixin: # Decorator for marking serialzier fields that can be filtered out def can_filter(func, default=False): """Decorator for marking serializer fields as filterable.""" + # Check if function is holding OptionalFilterabelSerializer somehow + if not issubclass(func.__class__, OptionalFilterabelSerializer): + return + if not isinstance(func, OptionalFilterabelSerializer): + return + # raise TypeError('can_filter can only be applied to OptionalFilterabelSerializer Serializers!') + if isinstance(func, serializers.ListSerializer): + return func func._kwargs['is_filterable'] = True func._kwargs['is_filterable_default'] = default return func @@ -269,7 +302,9 @@ class DependentField(serializers.Field): class InvenTreeModelSerializer( - OptionalFilterabelSerializer, serializers.ModelSerializer + FractionalFilterabelSerializer, + OptionalFilterabelSerializer, + serializers.ModelSerializer, ): """Inherits the standard Django ModelSerializer class, but also ensures that the underlying model class data are checked on validation."""