diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 310cf3b94f..9eb184b1c2 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -110,7 +110,7 @@ class PartThumbs(generics.ListAPIView): serializer_class = part_serializers.PartThumbSerializer - def list(self, reguest, *args, **kwargs): + def list(self, request, *args, **kwargs): """ Serialize the available Part images. - Images may be used for multiple parts! @@ -142,6 +142,7 @@ class PartDetail(generics.RetrieveUpdateAPIView): queryset = part_serializers.PartSerializer.prefetch_queryset(queryset) queryset = part_serializers.PartSerializer.annotate_queryset(queryset) + return queryset permission_classes = [ @@ -151,15 +152,13 @@ class PartDetail(generics.RetrieveUpdateAPIView): def get_serializer(self, *args, **kwargs): try: - cat_detail = str2bool(self.request.query_params.get('category_detail', False)) + kwargs['category_detail'] = str2bool(self.request.query_params.get('category_detail', False)) except AttributeError: - cat_detail = None + pass # Ensure the request context is passed through kwargs['context'] = self.get_serializer_context() - kwargs['category_detail'] = cat_detail - # Pass a list of "starred" parts fo the current user to the serializer # We do this to reduce the number of database queries required! if self.starred_parts is None and self.request is not None: @@ -206,8 +205,6 @@ class PartList(generics.ListCreateAPIView): # Ensure the request context is passed through kwargs['context'] = self.get_serializer_context() - kwargs['category_detail'] = cat_detail - # Pass a list of "starred" parts fo the current user to the serializer # We do this to reduce the number of database queries required! if self.starred_parts is None and self.request is not None: @@ -217,6 +214,63 @@ class PartList(generics.ListCreateAPIView): return self.serializer_class(*args, **kwargs) + def list(self, request, *args, **kwargs): + """ + Overide the 'list' method, as the PartCategory objects are + very expensive to serialize! + + So we will serialize them first, and keep them in memory, + so that they do not have to be serialized multiple times... + """ + + queryset = self.filter_queryset(self.get_queryset()) + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + + data = serializer.data + + # Do we wish to include PartCategory detail? + if str2bool(request.query_params.get('category_detail', False)): + + # Work out which part categorie we need to query + category_ids = set() + + for part in data: + cat_id = part['category'] + + if cat_id is not None: + category_ids.add(part['category']) + + # Fetch only the required PartCategory objects from the database + categories = PartCategory.objects.filter(pk__in=category_ids).prefetch_related( + 'parts', + 'parent', + 'children', + ) + + category_map = {} + + # Serialize each PartCategory object + for category in categories: + category_map[category.pk] = part_serializers.CategorySerializer(category).data + + for part in data: + cat_id = part['category'] + + if cat_id is not None and cat_id in category_map.keys(): + detail = category_map[part['category']] + else: + detail = None + + part['category_detail'] = detail + + return Response(data) + def create(self, request, *args, **kwargs): """ Override the default 'create' behaviour: We wish to save the user who created this part! diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index e713de455f..86a3189c43 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -101,6 +101,8 @@ class PartSerializer(InvenTreeModelSerializer): return queryset.prefetch_related( 'category', + 'category__parts', + 'category__parent', 'stock_items', 'bom_items', 'builds',