Update PartParameterTemplate API (#6538)

* Update PartParameterTemplate API

- Expose number of "parts" using a particular template
- Improve filtering visibility
- Update PUI table

* Update API version
This commit is contained in:
Oliver 2024-02-21 23:59:02 +11:00 committed by GitHub
parent 0bfbd45cec
commit defa03b83a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 67 additions and 45 deletions

View File

@ -1,11 +1,14 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 174 INVENTREE_API_VERSION = 175
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ INVENTREE_API_TEXT = """
v175 - 2024-02-21 : https://github.com/inventree/InvenTree/pull/6538
- Adds "parts" count to PartParameterTemplate serializer
v174 - 2024-02-21 : https://github.com/inventree/InvenTree/pull/6536 v174 - 2024-02-21 : https://github.com/inventree/InvenTree/pull/6536
- Expose PartCategory filters to the API documentation - Expose PartCategory filters to the API documentation
- Expose StockLocation filters to the API documentation - Expose StockLocation filters to the API documentation

View File

@ -1494,7 +1494,7 @@ class PartParameterTemplateFilter(rest_filters.FilterSet):
model = PartParameterTemplate model = PartParameterTemplate
# Simple filter fields # Simple filter fields
fields = ['units', 'checkbox'] fields = ['name', 'units', 'checkbox']
has_choices = rest_filters.BooleanFilter( has_choices = rest_filters.BooleanFilter(
method='filter_has_choices', label='Has Choice' method='filter_has_choices', label='Has Choice'
@ -1516,65 +1516,68 @@ class PartParameterTemplateFilter(rest_filters.FilterSet):
return queryset.filter(Q(units=None) | Q(units='')).distinct() return queryset.filter(Q(units=None) | Q(units='')).distinct()
part = rest_filters.ModelChoiceFilter(
queryset=Part.objects.all(), method='filter_part', label=_('Part')
)
class PartParameterTemplateList(ListCreateAPI): def filter_part(self, queryset, name, part):
"""Filter queryset to include only PartParameterTemplates which are referenced by a part."""
parameters = PartParameter.objects.filter(part=part)
template_ids = parameters.values_list('template').distinct()
return queryset.filter(pk__in=[el[0] for el in template_ids])
# Filter against a "PartCategory" - return only parameter templates which are referenced by parts in this category
category = rest_filters.ModelChoiceFilter(
queryset=PartCategory.objects.all(),
method='filter_category',
label=_('Category'),
)
def filter_category(self, queryset, name, category):
"""Filter queryset to include only PartParameterTemplates which are referenced by parts in this category."""
cats = category.get_descendants(include_self=True)
parameters = PartParameter.objects.filter(part__category__in=cats)
template_ids = parameters.values_list('template').distinct()
return queryset.filter(pk__in=[el[0] for el in template_ids])
class PartParameterTemplateMixin:
"""Mixin class for PartParameterTemplate API endpoints."""
queryset = PartParameterTemplate.objects.all()
serializer_class = part_serializers.PartParameterTemplateSerializer
def get_queryset(self, *args, **kwargs):
"""Return an annotated queryset for the PartParameterTemplateDetail endpoint."""
queryset = super().get_queryset(*args, **kwargs)
queryset = part_serializers.PartParameterTemplateSerializer.annotate_queryset(
queryset
)
return queryset
class PartParameterTemplateList(PartParameterTemplateMixin, ListCreateAPI):
"""API endpoint for accessing a list of PartParameterTemplate objects. """API endpoint for accessing a list of PartParameterTemplate objects.
- GET: Return list of PartParameterTemplate objects - GET: Return list of PartParameterTemplate objects
- POST: Create a new PartParameterTemplate object - POST: Create a new PartParameterTemplate object
""" """
queryset = PartParameterTemplate.objects.all()
serializer_class = part_serializers.PartParameterTemplateSerializer
filterset_class = PartParameterTemplateFilter filterset_class = PartParameterTemplateFilter
filter_backends = SEARCH_ORDER_FILTER filter_backends = SEARCH_ORDER_FILTER
filterset_fields = ['name']
search_fields = ['name', 'description'] search_fields = ['name', 'description']
ordering_fields = ['name', 'units', 'checkbox'] ordering_fields = ['name', 'units', 'checkbox', 'parts']
def filter_queryset(self, queryset):
"""Custom filtering for the PartParameterTemplate API."""
queryset = super().filter_queryset(queryset)
params = self.request.query_params
# Filtering against a "Part" - return only parameter templates which are referenced by a part
part = params.get('part', None)
if part is not None:
try:
part = Part.objects.get(pk=part)
parameters = PartParameter.objects.filter(part=part)
template_ids = parameters.values_list('template').distinct()
queryset = queryset.filter(pk__in=[el[0] for el in template_ids])
except (ValueError, Part.DoesNotExist):
pass
# Filtering against a "PartCategory" - return only parameter templates which are referenced by parts in this category
category = params.get('category', None)
if category is not None:
try:
category = PartCategory.objects.get(pk=category)
cats = category.get_descendants(include_self=True)
parameters = PartParameter.objects.filter(part__category__in=cats)
template_ids = parameters.values_list('template').distinct()
queryset = queryset.filter(pk__in=[el[0] for el in template_ids])
except (ValueError, PartCategory.DoesNotExist):
pass
return queryset
class PartParameterTemplateDetail(RetrieveUpdateDestroyAPI): class PartParameterTemplateDetail(PartParameterTemplateMixin, RetrieveUpdateDestroyAPI):
"""API endpoint for accessing the detail view for a PartParameterTemplate object.""" """API endpoint for accessing the detail view for a PartParameterTemplate object."""
queryset = PartParameterTemplate.objects.all() pass
serializer_class = part_serializers.PartParameterTemplateSerializer
class PartParameterAPIMixin: class PartParameterAPIMixin:

View File

@ -245,7 +245,18 @@ class PartParameterTemplateSerializer(InvenTree.serializers.InvenTreeModelSerial
"""Metaclass defining serializer fields.""" """Metaclass defining serializer fields."""
model = PartParameterTemplate model = PartParameterTemplate
fields = ['pk', 'name', 'units', 'description', 'checkbox', 'choices'] fields = ['pk', 'name', 'units', 'description', 'parts', 'checkbox', 'choices']
parts = serializers.IntegerField(
read_only=True,
label=_('Parts'),
help_text=_('Number of parts using this template'),
)
@staticmethod
def annotate_queryset(queryset):
"""Annotate the queryset with the number of parts which use each parameter template."""
return queryset.annotate(parts=SubqueryCount('instances'))
class PartBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer): class PartBriefSerializer(InvenTree.serializers.InvenTreeModelSerializer):

View File

@ -51,6 +51,11 @@ export default function PartParameterTemplateTable() {
sortable: true, sortable: true,
switchable: false switchable: false
}, },
{
accessor: 'parts',
sortable: true,
switchable: true
},
{ {
accessor: 'units', accessor: 'units',
sortable: true sortable: true