diff --git a/src/backend/InvenTree/InvenTree/mixins.py b/src/backend/InvenTree/InvenTree/mixins.py index d5512cabc0..43b5e0ab65 100644 --- a/src/backend/InvenTree/InvenTree/mixins.py +++ b/src/backend/InvenTree/InvenTree/mixins.py @@ -228,3 +228,12 @@ class OutputOptionsMixin: kwargs.update(self.output_options.format_params(params)) return super().get_serializer(*args, **kwargs) + + +class SerializerContextMixin: + """Mixin to add context to serializer.""" + + def get_serializer(self, *args, **kwargs): + """Add context to serializer.""" + kwargs['context'] = self.get_serializer_context() + return super().get_serializer(*args, **kwargs) diff --git a/src/backend/InvenTree/build/api.py b/src/backend/InvenTree/build/api.py index 005e0ab593..a1448afac7 100644 --- a/src/backend/InvenTree/build/api.py +++ b/src/backend/InvenTree/build/api.py @@ -39,6 +39,7 @@ from InvenTree.mixins import ( ListCreateAPI, OutputOptionsMixin, RetrieveUpdateDestroyAPI, + SerializerContextMixin, ) from users.models import Owner @@ -387,14 +388,7 @@ class BuildList(DataExportViewMixin, BuildMixin, ListCreateAPI): def get_serializer(self, *args, **kwargs): """Add extra context information to the endpoint serializer.""" - try: - part_detail = str2bool(self.request.GET.get('part_detail', True)) - except AttributeError: - part_detail = True - - kwargs['part_detail'] = part_detail kwargs['create'] = True - return super().get_serializer(*args, **kwargs) @@ -527,17 +521,12 @@ class BuildLineFilter(FilterSet): return queryset.exclude(flt) -class BuildLineMixin: +class BuildLineMixin(SerializerContextMixin): """Mixin class for BuildLine API endpoints.""" queryset = BuildLine.objects.all() serializer_class = build.serializers.BuildLineSerializer - def get_serializer(self, *args, **kwargs): - """Return the serializer instance for this endpoint.""" - kwargs['context'] = self.get_serializer_context() - return super().get_serializer(*args, **kwargs) - def get_source_build(self) -> Build: """Return the source Build object for the BuildLine queryset. diff --git a/src/backend/InvenTree/company/api.py b/src/backend/InvenTree/company/api.py index e5d23a5e9b..12e8a4c1e0 100644 --- a/src/backend/InvenTree/company/api.py +++ b/src/backend/InvenTree/company/api.py @@ -12,7 +12,12 @@ from data_exporter.mixins import DataExportViewMixin from InvenTree.api import ListCreateDestroyAPIView, MetadataView from InvenTree.fields import InvenTreeOutputOption, OutputConfiguration from InvenTree.filters import SEARCH_ORDER_FILTER, SEARCH_ORDER_FILTER_ALIAS -from InvenTree.mixins import ListCreateAPI, OutputOptionsMixin, RetrieveUpdateDestroyAPI +from InvenTree.mixins import ( + ListCreateAPI, + OutputOptionsMixin, + RetrieveUpdateDestroyAPI, + SerializerContextMixin, +) from .models import ( Address, @@ -170,7 +175,10 @@ class ManufacturerOutputOptions(OutputConfiguration): class ManufacturerPartList( - DataExportViewMixin, OutputOptionsMixin, ListCreateDestroyAPIView + SerializerContextMixin, + DataExportViewMixin, + OutputOptionsMixin, + ListCreateDestroyAPIView, ): """API endpoint for list view of ManufacturerPart object. @@ -181,13 +189,10 @@ class ManufacturerPartList( queryset = ManufacturerPart.objects.all().prefetch_related( 'part', 'manufacturer', 'supplier_parts', 'tags' ) - serializer_class = ManufacturerPartSerializer filterset_class = ManufacturerPartFilter output_options = ManufacturerOutputOptions - filter_backends = SEARCH_ORDER_FILTER - search_fields = [ 'manufacturer__name', 'description', @@ -242,16 +247,16 @@ class ManufacturerPartParameterOptions(OutputConfiguration): ] -class ManufacturerPartParameterList(ListCreateDestroyAPIView, OutputOptionsMixin): +class ManufacturerPartParameterList( + SerializerContextMixin, ListCreateDestroyAPIView, OutputOptionsMixin +): """API endpoint for list view of ManufacturerPartParamater model.""" queryset = ManufacturerPartParameter.objects.all() serializer_class = ManufacturerPartParameterSerializer filterset_class = ManufacturerPartParameterFilter output_options = ManufacturerPartParameterOptions - filter_backends = SEARCH_ORDER_FILTER - search_fields = ['name', 'value', 'units'] @@ -472,7 +477,7 @@ class SupplierPriceBreakOutputOptions(OutputConfiguration): ] -class SupplierPriceBreakList(OutputOptionsMixin, ListCreateAPI): +class SupplierPriceBreakList(SerializerContextMixin, OutputOptionsMixin, ListCreateAPI): """API endpoint for list view of SupplierPriceBreak object. - GET: Retrieve list of SupplierPriceBreak objects diff --git a/src/backend/InvenTree/order/api.py b/src/backend/InvenTree/order/api.py index 91f8c64b7d..b1dbbbfbfc 100644 --- a/src/backend/InvenTree/order/api.py +++ b/src/backend/InvenTree/order/api.py @@ -43,6 +43,7 @@ from InvenTree.mixins import ( ListCreateAPI, OutputOptionsMixin, RetrieveUpdateDestroyAPI, + SerializerContextMixin, ) from order import models, serializers from order.status_codes import ( @@ -57,22 +58,9 @@ from part.models import Part from users.models import Owner -class GeneralExtraLineList(DataExportViewMixin): +class GeneralExtraLineList(SerializerContextMixin, DataExportViewMixin): """General template for ExtraLine API classes.""" - def get_serializer(self, *args, **kwargs): - """Return the serializer instance for this endpoint.""" - try: - params = self.request.query_params3 - - kwargs['order_detail'] = str2bool(params.get('order_detail', False)) - except AttributeError: - pass - - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_queryset(self, *args, **kwargs): """Return the annotated queryset for this endpoint.""" queryset = super().get_queryset(*args, **kwargs) @@ -358,18 +346,12 @@ class PurchaseOrderOutputOptions(OutputConfiguration): OPTIONS = [InvenTreeOutputOption('supplier_detail')] -class PurchaseOrderMixin: +class PurchaseOrderMixin(SerializerContextMixin): """Mixin class for PurchaseOrder endpoints.""" queryset = models.PurchaseOrder.objects.all() serializer_class = serializers.PurchaseOrderSerializer - def get_serializer(self, *args, **kwargs): - """Return the serializer instance for this endpoint.""" - # Ensure the request context is passed through - kwargs['context'] = self.get_serializer_context() - return super().get_serializer(*args, **kwargs) - def get_queryset(self, *args, **kwargs): """Return the annotated queryset for this endpoint.""" queryset = super().get_queryset(*args, **kwargs) @@ -628,7 +610,7 @@ class PurchaseOrderLineItemOutputOptions(OutputConfiguration): ] -class PurchaseOrderLineItemMixin: +class PurchaseOrderLineItemMixin(SerializerContextMixin): """Mixin class for PurchaseOrderLineItem endpoints.""" queryset = models.PurchaseOrderLineItem.objects.all() @@ -644,12 +626,6 @@ class PurchaseOrderLineItemMixin: return queryset - def get_serializer(self, *args, **kwargs): - """Return serializer instance for this endpoint.""" - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def perform_update(self, serializer): """Override the perform_update method to auto-update pricing if required.""" super().perform_update(serializer) @@ -831,19 +807,12 @@ class SalesOrderFilter(OrderFilter): ) -class SalesOrderMixin: +class SalesOrderMixin(SerializerContextMixin): """Mixin class for SalesOrder endpoints.""" queryset = models.SalesOrder.objects.all() serializer_class = serializers.SalesOrderSerializer - def get_serializer(self, *args, **kwargs): - """Return serializer instance for this endpoint.""" - # Ensure the context is passed through to the serializer - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_queryset(self, *args, **kwargs): """Return annotated queryset for this endpoint.""" queryset = super().get_queryset(*args, **kwargs) @@ -1022,18 +991,12 @@ class SalesOrderLineItemFilter(LineItemFilter): return queryset.exclude(order__status__in=SalesOrderStatusGroups.OPEN) -class SalesOrderLineItemMixin: +class SalesOrderLineItemMixin(SerializerContextMixin): """Mixin class for SalesOrderLineItem endpoints.""" queryset = models.SalesOrderLineItem.objects.all() serializer_class = serializers.SalesOrderLineItemSerializer - def get_serializer(self, *args, **kwargs): - """Return serializer for this endpoint with extra data as requested.""" - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_queryset(self, *args, **kwargs): """Return annotated queryset for this endpoint.""" queryset = super().get_queryset(*args, **kwargs) @@ -1493,19 +1456,12 @@ class ReturnOrderFilter(OrderFilter): ) -class ReturnOrderMixin: +class ReturnOrderMixin(SerializerContextMixin): """Mixin class for ReturnOrder endpoints.""" queryset = models.ReturnOrder.objects.all() serializer_class = serializers.ReturnOrderSerializer - def get_serializer(self, *args, **kwargs): - """Return serializer instance for this endpoint.""" - # Ensure the context is passed through to the serializer - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_queryset(self, *args, **kwargs): """Return annotated queryset for this endpoint.""" queryset = super().get_queryset(*args, **kwargs) @@ -1650,18 +1606,12 @@ class ReturnOrderLineItemFilter(LineItemFilter): return queryset.filter(received_date=None) -class ReturnOrderLineItemMixin: +class ReturnOrderLineItemMixin(SerializerContextMixin): """Mixin class for ReturnOrderLineItem endpoints.""" queryset = models.ReturnOrderLineItem.objects.all() serializer_class = serializers.ReturnOrderLineItemSerializer - def get_serializer(self, *args, **kwargs): - """Return serializer for this endpoint with extra data as requested.""" - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_queryset(self, *args, **kwargs): """Return annotated queryset for this endpoint.""" queryset = super().get_queryset(*args, **kwargs) diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py index 2eb53025e9..56bed73f85 100644 --- a/src/backend/InvenTree/part/api.py +++ b/src/backend/InvenTree/part/api.py @@ -43,6 +43,7 @@ from InvenTree.mixins import ( RetrieveAPI, RetrieveUpdateAPI, RetrieveUpdateDestroyAPI, + SerializerContextMixin, UpdateAPI, ) from InvenTree.serializers import EmptySerializer @@ -1014,7 +1015,7 @@ class PartFilter(FilterSet): return queryset.filter(category__in=children) -class PartMixin: +class PartMixin(SerializerContextMixin): """Mixin class for Part API endpoints.""" serializer_class = part_serializers.PartSerializer @@ -1037,9 +1038,6 @@ class PartMixin: def get_serializer(self, *args, **kwargs): """Return a serializer instance for this endpoint.""" - # Ensure the request context is passed through - kwargs['context'] = self.get_serializer_context() - # Indicate that we can create a new Part via this endpoint kwargs['create'] = self.is_create @@ -1053,7 +1051,6 @@ class PartMixin: self.starred_parts = [ star.part for star in self.request.user.starred_parts.all() ] - kwargs['starred_parts'] = self.starred_parts return super().get_serializer(*args, **kwargs) @@ -1387,23 +1384,6 @@ class PartParameterAPIMixin: return context - def get_serializer(self, *args, **kwargs): - """Return the serializer instance for this API endpoint. - - If requested, extra detail fields are annotated to the queryset: - - part_detail - - template_detail - """ - try: - kwargs['part_detail'] = str2bool(self.request.GET.get('part_detail', False)) - kwargs['template_detail'] = str2bool( - self.request.GET.get('template_detail', True) - ) - except AttributeError: - pass - - return super().get_serializer(*args, **kwargs) - class PartParameterFilter(FilterSet): """Custom filters for the PartParameterList API endpoint.""" @@ -1614,19 +1594,12 @@ class BomFilter(FilterSet): return queryset.filter(part.get_used_in_bom_item_filter()) -class BomMixin: +class BomMixin(SerializerContextMixin): """Mixin class for BomItem API endpoints.""" serializer_class = part_serializers.BomItemSerializer queryset = BomItem.objects.all() - def get_serializer(self, *args, **kwargs): - """Return the serializer instance for this API endpoint.""" - # Ensure the request context is passed through! - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_queryset(self, *args, **kwargs): """Return the queryset object for this endpoint.""" queryset = super().get_queryset(*args, **kwargs) diff --git a/src/backend/InvenTree/stock/api.py b/src/backend/InvenTree/stock/api.py index 76a16a6ab2..bc7ce58d91 100644 --- a/src/backend/InvenTree/stock/api.py +++ b/src/backend/InvenTree/stock/api.py @@ -52,6 +52,7 @@ from InvenTree.mixins import ( OutputOptionsMixin, RetrieveAPI, RetrieveUpdateDestroyAPI, + SerializerContextMixin, ) from order.models import PurchaseOrder, ReturnOrder, SalesOrder from order.serializers import ( @@ -373,18 +374,12 @@ class StockLocationFilter(FilterSet): return queryset -class StockLocationMixin: +class StockLocationMixin(SerializerContextMixin): """Mixin class for StockLocation API endpoints.""" queryset = StockLocation.objects.all() serializer_class = StockSerializers.LocationSerializer - def get_serializer(self, *args, **kwargs): - """Set context before returning serializer.""" - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_queryset(self, *args, **kwargs): """Return annotated queryset for the StockLocationList endpoint.""" queryset = super().get_queryset(*args, **kwargs) @@ -1012,7 +1007,7 @@ class StockFilter(FilterSet): return queryset.filter(location__in=children) -class StockApiMixin: +class StockApiMixin(SerializerContextMixin): """Mixin class for StockItem API endpoints.""" serializer_class = StockSerializers.StockItemSerializer @@ -1032,12 +1027,6 @@ class StockApiMixin: return ctx - def get_serializer(self, *args, **kwargs): - """Set context before returning serializer.""" - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - class StockOutputOptions(OutputConfiguration): """Output options for StockItem serializers.""" @@ -1317,7 +1306,7 @@ class StockItemSerialNumbers(RetrieveAPI): serializer_class = StockSerializers.StockItemSerialNumbersSerializer -class StockItemTestResultMixin: +class StockItemTestResultMixin(SerializerContextMixin): """Mixin class for the StockItemTestResult API endpoints.""" queryset = StockItemTestResult.objects.all() @@ -1329,12 +1318,6 @@ class StockItemTestResultMixin: ctx['request'] = self.request return ctx - def get_serializer(self, *args, **kwargs): - """Set context before returning serializer.""" - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - class StockItemTestResultOutputOptions(OutputConfiguration): """Output options for StockItemTestResult endpoint.""" @@ -1487,7 +1470,9 @@ class StockTrackingOutputOptions(OutputConfiguration): ] -class StockTrackingList(DataExportViewMixin, OutputOptionsMixin, ListAPI): +class StockTrackingList( + SerializerContextMixin, DataExportViewMixin, OutputOptionsMixin, ListAPI +): """API endpoint for list view of StockItemTracking objects. StockItemTracking objects are read-only @@ -1500,12 +1485,6 @@ class StockTrackingList(DataExportViewMixin, OutputOptionsMixin, ListAPI): serializer_class = StockSerializers.StockTrackingSerializer output_options = StockTrackingOutputOptions - def get_serializer(self, *args, **kwargs): - """Set context before returning serializer.""" - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_delta_model_map(self) -> dict: """Return a mapping of delta models to their respective models and serializers. diff --git a/src/backend/InvenTree/users/api.py b/src/backend/InvenTree/users/api.py index 39bfd595d4..71456fa9dc 100644 --- a/src/backend/InvenTree/users/api.py +++ b/src/backend/InvenTree/users/api.py @@ -30,6 +30,7 @@ from InvenTree.mixins import ( RetrieveAPI, RetrieveUpdateAPI, RetrieveUpdateDestroyAPI, + SerializerContextMixin, UpdateAPI, ) from InvenTree.settings import FRONTEND_URL_BASE @@ -278,7 +279,7 @@ class UserList(ListCreateAPI): filterset_fields = ['is_staff', 'is_active', 'is_superuser'] -class GroupMixin: +class GroupMixin(SerializerContextMixin): """Mixin for Group API endpoints to add permissions filter. Permissions: @@ -290,12 +291,6 @@ class GroupMixin: serializer_class = GroupSerializer permission_classes = [InvenTree.permissions.IsStaffOrReadOnlyScope] - def get_serializer(self, *args, **kwargs): - """Return serializer instance for this endpoint.""" - kwargs['context'] = self.get_serializer_context() - - return super().get_serializer(*args, **kwargs) - def get_queryset(self): """Return queryset for this endpoint.