mirror of
https://github.com/inventree/InvenTree.git
synced 2025-10-14 21:22:20 +00:00
refactor(backend): move serializer context enrichment to mixin (#10456)
* add output options for PurchaseOrder, SalesOrder, and ReturnOrder endpoints * add output options for PurchaseOrder, SalesOrder, and ReturnOrder endpoints * add serializer context handling and update sales order fixture with additional line item * bump API version to 398 and update output options tests for PurchaseOrder endpoint * refactor(backend): move serializer context enrichtment to mixin * cleanup other get_serializer instances * add output options tests for SalesOrder and ReturnOrder detail endpoints * fix typo * fix api --------- Co-authored-by: Silver <reza.sh.7798@gmail.com>
This commit is contained in:
@@ -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)
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
Reference in New Issue
Block a user