2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-10-24 09:57:40 +00:00

make safer to use with various sanity checks

This commit is contained in:
Matthias Mair
2025-10-14 12:57:50 +02:00
parent 70df5cc89a
commit ff307e70ee
2 changed files with 23 additions and 26 deletions

View File

@@ -14,6 +14,7 @@ from InvenTree.helpers import (
strip_html_tags, strip_html_tags,
) )
from InvenTree.schema import schema_for_view_output_options from InvenTree.schema import schema_for_view_output_options
from InvenTree.serializers import PathScopedMixin
class CleanMixin: class CleanMixin:
@@ -227,7 +228,15 @@ class OutputOptionsMixin:
params = self.request.query_params params = self.request.query_params
kwargs.update(self.output_options.format_params(params)) kwargs.update(self.output_options.format_params(params))
return super().get_serializer(*args, **kwargs) serializer = super().get_serializer(*args, **kwargs)
# Check if the serializer actually can be filtered - makes not much sense to use this mixin without that prerequisite
if not isinstance(serializer, PathScopedMixin):
raise Exception(
'INVE-W999: `OutputOptionsMixin` can only be used with serializers that contain the `PathScopedMixin` mixin'
)
return serializer
class SerializerContextMixin: class SerializerContextMixin:

View File

@@ -39,15 +39,10 @@ class OptFilter:
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"""Initialize the serializer.""" """Initialize the serializer."""
# Set filterable options for future ref if self.is_filterable is None: # Materialize parameters for later usage
if self.is_filterable is None:
self.is_filterable = kwargs.pop('is_filterable', None) self.is_filterable = kwargs.pop('is_filterable', None)
self.is_filterable_vals = kwargs.pop('is_filterable_vals', {}) self.is_filterable_vals = kwargs.pop('is_filterable_vals', {})
# remove filter args from kwargs
# TODO remove: kwargs = PathScopedMixin.gather_filters(self, kwargs)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# TODO remove: PathScopedMixin.do_filtering(self, *args, **kwargs)
class PathScopedMixin: class PathScopedMixin:
@@ -86,17 +81,16 @@ class PathScopedMixin:
tgs_vals[k] = str2bool(val) if isinstance(val, str) else val tgs_vals[k] = str2bool(val) if isinstance(val, str) else val
self.filter_target_values = tgs_vals self.filter_target_values = tgs_vals
# TODO remove
if len(self.filter_targets) == 0: if len(self.filter_targets) == 0:
raise ValueError('No filter targets found') raise Exception(
'INVE-W999: No filter targets found in fields, remove `PathScopedMixin`'
)
return kwargs return kwargs
def do_filtering(self, *args, **kwargs): def do_filtering(self, *args, **kwargs):
"""Do the actual filtering.""" """Do the actual filtering."""
if InvenTree.ready.isGeneratingSchema() or not hasattr( if not hasattr(self, 'filter_target_values'):
self, 'filter_target_values'
):
return return
# Throw out fields which are not requested # Throw out fields which are not requested
@@ -109,28 +103,22 @@ class PathScopedMixin:
# Decorator for marking serialzier fields that can be filtered out # Decorator for marking serialzier fields that can be filtered out
def can_filter(func, default=False, name: Optional[str] = None): def can_filter(func, default=False, name: Optional[str] = None):
"""Decorator for marking serializer fields as filterable.""" """Decorator for marking serializer fields as filterable."""
is_field = False # Ensure this function can be actually filteres
# Check if function is holding OptionalFilterabelSerializer somehow
if not issubclass(func.__class__, OptFilter): if not issubclass(func.__class__, OptFilter):
raise TypeError( raise TypeError(
'can_filter can only be applied to OptionalFilterabelSerializer Serializers!' 'INVE-W999: `can_filter` can only be applied to serializers that contain `OptFilter` mixin!'
) )
# Mark the function as filterable # Mark the function as filterable
values = {'default': default, 'name': name if name else func.field_name} func._kwargs['is_filterable'] = True
func._kwargs['is_filterable_vals'] = {
if is_field: 'default': default,
pass 'name': name if name else func.field_name,
# print(func) }
# func.is_filterable = True
# func.is_filterable_vals = values
else:
func._kwargs['is_filterable'] = True
func._kwargs['is_filterable_vals'] = values
return func return func
class FilterableListSerializer(OptFilter, serializers.ListSerializer): class FilterableListSerializer(OptFilter, PathScopedMixin, serializers.ListSerializer):
"""Custom ListSerializer which allows filtering of fields.""" """Custom ListSerializer which allows filtering of fields."""