mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Custom aggregation of Part API
- Reduced full part query from 2.5s to 200ms!
This commit is contained in:
parent
37dba91b4a
commit
79cd05423c
@ -6,6 +6,9 @@ Provides a JSON API for the Part app
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django.conf import settings
|
||||
|
||||
from django.db.models import Sum
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
@ -15,6 +18,8 @@ from rest_framework import generics, permissions
|
||||
from django.conf.urls import url, include
|
||||
from django.urls import reverse
|
||||
|
||||
import os
|
||||
|
||||
from .models import Part, PartCategory, BomItem, PartStar
|
||||
|
||||
from .serializers import PartSerializer, BomItemSerializer
|
||||
@ -99,6 +104,61 @@ class PartList(generics.ListCreateAPIView):
|
||||
|
||||
serializer_class = PartSerializer
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""
|
||||
Instead of using the DRF serialiser to LIST,
|
||||
we serialize the objects manuually.
|
||||
This turns out to be significantly faster.
|
||||
"""
|
||||
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
|
||||
data = queryset.values(
|
||||
'pk',
|
||||
'category',
|
||||
'image',
|
||||
'name',
|
||||
'IPN',
|
||||
'description',
|
||||
'keywords',
|
||||
'is_template',
|
||||
'URL',
|
||||
'units',
|
||||
'trackable',
|
||||
'assembly',
|
||||
'component',
|
||||
'salable',
|
||||
'active',
|
||||
).annotate(
|
||||
in_stock=Sum('stock_items__quantity'),
|
||||
)
|
||||
|
||||
# TODO - Annotate total being built
|
||||
# TODO - Annotate total on order
|
||||
# TODO - Annotate
|
||||
|
||||
# Reduce the number of lookups we need to do for the part categories
|
||||
categories = {}
|
||||
|
||||
for item in data:
|
||||
|
||||
if item['image']:
|
||||
item['image'] = os.path.join(settings.MEDIA_URL, item['image'])
|
||||
|
||||
cat_id = item['category']
|
||||
|
||||
if cat_id:
|
||||
if cat_id not in categories:
|
||||
categories[cat_id] = PartCategory.objects.get(pk=cat_id).pathstring
|
||||
|
||||
item['category__name'] = categories[cat_id]
|
||||
else:
|
||||
item['category__name'] = None
|
||||
|
||||
|
||||
return Response(data)
|
||||
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
# Does the user wish to filter by category?
|
||||
|
@ -112,16 +112,25 @@ function loadPartTable(table, url, options={}) {
|
||||
}
|
||||
|
||||
columns.push({
|
||||
field: 'full_name',
|
||||
field: 'name',
|
||||
title: 'Part',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
|
||||
if (row.is_template) {
|
||||
value = '<i>' + value + '</i>';
|
||||
var name = '';
|
||||
|
||||
if (row.IPN) {
|
||||
name += row.IPN;
|
||||
name += ' | ';
|
||||
}
|
||||
|
||||
var display = imageHoverIcon(row.image_url) + renderLink(value, row.url);
|
||||
name += value;
|
||||
|
||||
if (row.is_template) {
|
||||
name = '<i>' + name + '</i>';
|
||||
}
|
||||
|
||||
var display = imageHoverIcon(row.image) + renderLink(name, '/part/' + row.pk + '/');
|
||||
|
||||
if (!row.active) {
|
||||
display = display + "<span class='label label-warning' style='float: right;'>INACTIVE</span>";
|
||||
@ -146,11 +155,11 @@ function loadPartTable(table, url, options={}) {
|
||||
|
||||
columns.push({
|
||||
sortable: true,
|
||||
field: 'category_name',
|
||||
field: 'category__name',
|
||||
title: 'Category',
|
||||
formatter: function(value, row, index, field) {
|
||||
if (row.category) {
|
||||
return renderLink(row.category_name, "/part/category/" + row.category + "/");
|
||||
return renderLink(row.category__name, "/part/category/" + row.category + "/");
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
@ -159,13 +168,13 @@ function loadPartTable(table, url, options={}) {
|
||||
});
|
||||
|
||||
columns.push({
|
||||
field: 'total_stock',
|
||||
field: 'in_stock',
|
||||
title: 'Stock',
|
||||
searchable: false,
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
if (value) {
|
||||
return renderLink(value, row.url + 'stock/');
|
||||
return renderLink(value, '/part/' + row.pk + '/stock/');
|
||||
}
|
||||
else {
|
||||
return "<span class='label label-warning'>No Stock</span>";
|
||||
|
Loading…
Reference in New Issue
Block a user