From 6a89e0089d1a5d853e30b90a5495cbb681c63182 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 20 Apr 2020 00:49:13 +1000 Subject: [PATCH] Updates for stock serializer --- InvenTree/part/api.py | 7 +++ InvenTree/part/serializers.py | 5 +- InvenTree/stock/api.py | 88 +++++++--------------------------- InvenTree/stock/serializers.py | 34 ++++++++----- 4 files changed, 45 insertions(+), 89 deletions(-) diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 6eda5539dd..3169c613ca 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -205,6 +205,13 @@ class PartList(generics.ListCreateAPIView): headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + def get_queryset(self, *args, **kwargs): + + queryset = super().get_queryset(*args, **kwargs) + queryset = part_serializers.PartSerializer.prefetch_queryset(queryset) + + return queryset + def filter_queryset(self, queryset): """ Perform custom filtering of the queryset diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 23e85df1a4..7ad1b83aa8 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -113,10 +113,7 @@ class PartSerializer(InvenTreeModelSerializer): 'builds', 'supplier_parts', 'supplier_parts__purchase_order_line_items', - 'supplier_parts__purcahes_order_line_items__order', - 'starred_users', - 'starred_user__user', - 'starred_user__part', + 'supplier_parts__purchase_order_line_items__order', ) @staticmethod diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 9f485ba5f7..1e27848eb9 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -317,100 +317,44 @@ class StockList(generics.ListCreateAPIView): - status: Filter by the StockItem status """ + serializer_class = StockItemSerializer + queryset = StockItem.objects.all() def get_serializer(self, *args, **kwargs): try: - part_detail = str2bool(self.request.GET.get('part_detail', None)) - location_detail = str2bool(self.request.GET.get('location_detail', None)) + part_detail = str2bool(self.request.query_params.get('part_detail', None)) + location_detail = str2bool(self.request.query_params.get('location_detail', None)) + supplier_part_detail = str2bool(self.request.query_params.get('supplier_part_detail', None)) except AttributeError: part_detail = None location_detail = None + supplier_part_detail = None kwargs['part_detail'] = part_detail kwargs['location_detail'] = location_detail + # Ensure the request context is passed through kwargs['context'] = self.get_serializer_context() + return self.serializer_class(*args, **kwargs) - def list(self, request, *args, **kwargs): + # TODO - Override the 'create' method for this view, + # to allow the user to be recorded when a new StockItem object is created - queryset = self.filter_queryset(self.get_queryset()) + def get_queryset(self, *args, **kwargs): - # Instead of using the DRF serializer to LIST, - # we will serialize the objects manually. - # This is significantly faster + queryset = super().get_queryset(*args, **kwargs) + queryset = StockItemSerializer.prefetch_queryset(queryset) - data = queryset.values( - 'pk', - 'uid', - 'parent', - 'quantity', - 'serial', - 'batch', - 'status', - 'notes', - 'link', - 'location', - 'location__name', - 'location__description', - 'part', - 'part__IPN', - 'part__name', - 'part__revision', - 'part__description', - 'part__image', - 'part__category', - 'part__category__name', - 'part__category__description', - 'supplier_part', - ) + return queryset - # Reduce the number of lookups we need to do for categories - # Cache location lookups for this query - locations = {} - for item in data: - - img = item['part__image'] - - if img: - # Use the thumbnail image instead - fn, ext = os.path.splitext(img) - - thumb = "{fn}.thumbnail{ext}".format(fn=fn, ext=ext) - - thumb = os.path.join(settings.MEDIA_URL, thumb) - else: - thumb = '' - - item['part__thumbnail'] = thumb - - del item['part__image'] - - loc_id = item['location'] - - if loc_id: - if loc_id not in locations: - locations[loc_id] = StockLocation.objects.get(pk=loc_id).pathstring - - item['location__path'] = locations[loc_id] - else: - item['location__path'] = None - - item['status_text'] = StockStatus.label(item['status']) - - return Response(data) - - def get_queryset(self): - """ - If the query includes a particular location, - we may wish to also request stock items from all child locations. - """ + def filter_queryset(self, queryset): # Start with all objects - stock_list = super(StockList, self).get_queryset() + stock_list = super().filter_queryset(queryset) # Filter out parts which are not actually "in stock" stock_list = stock_list.filter(customer=None, belongs_to=None) diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index fe4f850658..a7b51672c4 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -56,18 +56,28 @@ class StockItemSerializer(InvenTreeModelSerializer): - Includes serialization for the item location """ - url = serializers.CharField(source='get_absolute_url', read_only=True) + @staticmethod + def prefetch_queryset(queryset): + """ + Prefetch related database tables, + to reduce database hits. + """ + + return queryset.prefetch_related( + 'supplier_part', + 'supplier_part__supplier', + 'supplier_part__manufacturer', + 'location', + 'part' + ) + status_text = serializers.CharField(source='get_status_display', read_only=True) - part_name = serializers.CharField(source='get_part_name', read_only=True) - - part_image = serializers.CharField(source='part__image', read_only=True) - - tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True) + #tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True) part_detail = PartBriefSerializer(source='part', many=False, read_only=True) location_detail = LocationBriefSerializer(source='location', many=False, read_only=True) - supplier_detail = SupplierPartSerializer(source='supplier_part', many=False, read_only=True) + supplier_part_detail = SupplierPartSerializer(source='supplier_part', many=False, read_only=True) def __init__(self, *args, **kwargs): @@ -84,7 +94,7 @@ class StockItemSerializer(InvenTreeModelSerializer): self.fields.pop('location_detail') if supplier_detail is not True: - self.fields.pop('supplier_detail') + self.fields.pop('supplier_part_detail') class Meta: model = StockItem @@ -97,18 +107,16 @@ class StockItemSerializer(InvenTreeModelSerializer): 'notes', 'part', 'part_detail', - 'part_name', - 'part_image', 'pk', 'quantity', 'serial', 'supplier_part', - 'supplier_detail', + 'supplier_part_detail', 'status', 'status_text', - 'tracking_items', + #'tracking_items', 'uid', - 'url', + #'url', ] """ These fields are read-only in this context.