Updates for stock serializer

This commit is contained in:
Oliver Walters 2020-04-20 00:49:13 +10:00
parent 5233281a24
commit 6a89e0089d
4 changed files with 45 additions and 89 deletions

View File

@ -205,6 +205,13 @@ class PartList(generics.ListCreateAPIView):
headers = self.get_success_headers(serializer.data) headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) 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): def filter_queryset(self, queryset):
""" """
Perform custom filtering of the queryset Perform custom filtering of the queryset

View File

@ -113,10 +113,7 @@ class PartSerializer(InvenTreeModelSerializer):
'builds', 'builds',
'supplier_parts', 'supplier_parts',
'supplier_parts__purchase_order_line_items', 'supplier_parts__purchase_order_line_items',
'supplier_parts__purcahes_order_line_items__order', 'supplier_parts__purchase_order_line_items__order',
'starred_users',
'starred_user__user',
'starred_user__part',
) )
@staticmethod @staticmethod

View File

@ -317,100 +317,44 @@ class StockList(generics.ListCreateAPIView):
- status: Filter by the StockItem status - status: Filter by the StockItem status
""" """
serializer_class = StockItemSerializer
queryset = StockItem.objects.all() queryset = StockItem.objects.all()
def get_serializer(self, *args, **kwargs): def get_serializer(self, *args, **kwargs):
try: try:
part_detail = str2bool(self.request.GET.get('part_detail', None)) part_detail = str2bool(self.request.query_params.get('part_detail', None))
location_detail = str2bool(self.request.GET.get('location_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: except AttributeError:
part_detail = None part_detail = None
location_detail = None location_detail = None
supplier_part_detail = None
kwargs['part_detail'] = part_detail kwargs['part_detail'] = part_detail
kwargs['location_detail'] = location_detail kwargs['location_detail'] = location_detail
# Ensure the request context is passed through
kwargs['context'] = self.get_serializer_context() kwargs['context'] = self.get_serializer_context()
return self.serializer_class(*args, **kwargs) 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, queryset = super().get_queryset(*args, **kwargs)
# we will serialize the objects manually. queryset = StockItemSerializer.prefetch_queryset(queryset)
# This is significantly faster
data = queryset.values( return queryset
'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',
)
# Reduce the number of lookups we need to do for categories
# Cache location lookups for this query
locations = {}
for item in data: def filter_queryset(self, queryset):
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.
"""
# Start with all objects # 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" # Filter out parts which are not actually "in stock"
stock_list = stock_list.filter(customer=None, belongs_to=None) stock_list = stock_list.filter(customer=None, belongs_to=None)

View File

@ -56,18 +56,28 @@ class StockItemSerializer(InvenTreeModelSerializer):
- Includes serialization for the item location - 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) status_text = serializers.CharField(source='get_status_display', read_only=True)
part_name = serializers.CharField(source='get_part_name', read_only=True) #tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True)
part_image = serializers.CharField(source='part__image', read_only=True)
tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True)
part_detail = PartBriefSerializer(source='part', many=False, read_only=True) part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
location_detail = LocationBriefSerializer(source='location', 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): def __init__(self, *args, **kwargs):
@ -84,7 +94,7 @@ class StockItemSerializer(InvenTreeModelSerializer):
self.fields.pop('location_detail') self.fields.pop('location_detail')
if supplier_detail is not True: if supplier_detail is not True:
self.fields.pop('supplier_detail') self.fields.pop('supplier_part_detail')
class Meta: class Meta:
model = StockItem model = StockItem
@ -97,18 +107,16 @@ class StockItemSerializer(InvenTreeModelSerializer):
'notes', 'notes',
'part', 'part',
'part_detail', 'part_detail',
'part_name',
'part_image',
'pk', 'pk',
'quantity', 'quantity',
'serial', 'serial',
'supplier_part', 'supplier_part',
'supplier_detail', 'supplier_part_detail',
'status', 'status',
'status_text', 'status_text',
'tracking_items', #'tracking_items',
'uid', 'uid',
'url', #'url',
] ]
""" These fields are read-only in this context. """ These fields are read-only in this context.