mirror of
https://github.com/inventree/InvenTree.git
synced 2025-12-17 09:48:30 +00:00
[API] API refactoring (#11023)
* API refactoring - Specify prefetch_fields for optional child serializers - Ref: https://github.com/inventree/InvenTree/pull/11012/ * Fixes for unit tests
This commit is contained in:
@@ -1,11 +1,15 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 432
|
INVENTREE_API_VERSION = 433
|
||||||
"""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 = """
|
||||||
|
|
||||||
|
v433 -> 2025-12-16 : https://github.com/inventree/InvenTree/pull/11023
|
||||||
|
- "substitutes" field on the BomItem API endpoint is now excluded by default
|
||||||
|
- Add "?substitutes=true" query parameter to include substitute parts in BomItem API endpoint(s)
|
||||||
|
|
||||||
v432 -> 2025-12-15 : https://github.com/inventree/InvenTree/pull/11012
|
v432 -> 2025-12-15 : https://github.com/inventree/InvenTree/pull/11012
|
||||||
- The "part_detail" field on the SupplierPart API endpoint is now optional
|
- The "part_detail" field on the SupplierPart API endpoint is now optional
|
||||||
- The "supplier_detail" field on the SupplierPart API endpoint is now optional
|
- The "supplier_detail" field on the SupplierPart API endpoint is now optional
|
||||||
|
|||||||
@@ -1435,6 +1435,7 @@ class BuildLineSerializer(
|
|||||||
can_build=False,
|
can_build=False,
|
||||||
),
|
),
|
||||||
False,
|
False,
|
||||||
|
prefetch_fields=['bom_item'],
|
||||||
)
|
)
|
||||||
|
|
||||||
assembly_detail = enable_filter(
|
assembly_detail = enable_filter(
|
||||||
|
|||||||
@@ -893,9 +893,7 @@ class ParameterFilter(FilterSet):
|
|||||||
class ParameterMixin:
|
class ParameterMixin:
|
||||||
"""Mixin class for Parameter views."""
|
"""Mixin class for Parameter views."""
|
||||||
|
|
||||||
queryset = common.models.Parameter.objects.all().prefetch_related(
|
queryset = common.models.Parameter.objects.all().prefetch_related('model_type')
|
||||||
'model_type', 'updated_by', 'template', 'template__model_type'
|
|
||||||
)
|
|
||||||
serializer_class = common.serializers.ParameterSerializer
|
serializer_class = common.serializers.ParameterSerializer
|
||||||
permission_classes = [IsAuthenticatedOrReadScope]
|
permission_classes = [IsAuthenticatedOrReadScope]
|
||||||
|
|
||||||
|
|||||||
@@ -808,11 +808,15 @@ class ParameterSerializer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
updated_by_detail = enable_filter(
|
updated_by_detail = enable_filter(
|
||||||
UserSerializer(source='updated_by', read_only=True, many=False), True
|
UserSerializer(source='updated_by', read_only=True, many=False),
|
||||||
|
True,
|
||||||
|
prefetch_fields=['updated_by'],
|
||||||
)
|
)
|
||||||
|
|
||||||
template_detail = enable_filter(
|
template_detail = enable_filter(
|
||||||
ParameterTemplateSerializer(source='template', read_only=True, many=False), True
|
ParameterTemplateSerializer(source='template', read_only=True, many=False),
|
||||||
|
True,
|
||||||
|
prefetch_fields=['template', 'template__model_type'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -430,13 +430,6 @@ class SupplierPriceBreakMixin:
|
|||||||
queryset = SupplierPriceBreak.objects.all()
|
queryset = SupplierPriceBreak.objects.all()
|
||||||
serializer_class = SupplierPriceBreakSerializer
|
serializer_class = SupplierPriceBreakSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
"""Return annotated queryset for the SupplierPriceBreak list endpoint."""
|
|
||||||
queryset = super().get_queryset()
|
|
||||||
queryset = SupplierPriceBreakSerializer.annotate_queryset(queryset)
|
|
||||||
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
|
|
||||||
class SupplierPriceBreakOutputOptions(OutputConfiguration):
|
class SupplierPriceBreakOutputOptions(OutputConfiguration):
|
||||||
"""Available output options for the SupplierPriceBreak endpoints."""
|
"""Available output options for the SupplierPriceBreak endpoints."""
|
||||||
|
|||||||
@@ -572,7 +572,9 @@ class SupplierPriceBreakSerializer(
|
|||||||
supplier_detail = enable_filter(
|
supplier_detail = enable_filter(
|
||||||
CompanyBriefSerializer(
|
CompanyBriefSerializer(
|
||||||
source='part.supplier', many=False, read_only=True, allow_null=True
|
source='part.supplier', many=False, read_only=True, allow_null=True
|
||||||
)
|
),
|
||||||
|
False,
|
||||||
|
prefetch_fields=['part__supplier'],
|
||||||
)
|
)
|
||||||
|
|
||||||
part_detail = enable_filter(
|
part_detail = enable_filter(
|
||||||
@@ -580,4 +582,5 @@ class SupplierPriceBreakSerializer(
|
|||||||
source='part', brief=True, many=False, read_only=True, allow_null=True
|
source='part', brief=True, many=False, read_only=True, allow_null=True
|
||||||
),
|
),
|
||||||
False,
|
False,
|
||||||
|
prefetch_fields=['part', 'part__part', 'part__part__pricing_data'],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -570,7 +570,7 @@ class PartPricingDetail(RetrieveUpdateAPI):
|
|||||||
"""API endpoint for viewing part pricing data."""
|
"""API endpoint for viewing part pricing data."""
|
||||||
|
|
||||||
serializer_class = part_serializers.PartPricingSerializer
|
serializer_class = part_serializers.PartPricingSerializer
|
||||||
queryset = Part.objects.all()
|
queryset = Part.objects.all().select_related('pricing_data')
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
"""Return the PartPricing object associated with the linked Part."""
|
"""Return the PartPricing object associated with the linked Part."""
|
||||||
@@ -1361,6 +1361,8 @@ class BomOutputOptions(OutputConfiguration):
|
|||||||
InvenTreeOutputOption('can_build', default=True),
|
InvenTreeOutputOption('can_build', default=True),
|
||||||
InvenTreeOutputOption('part_detail'),
|
InvenTreeOutputOption('part_detail'),
|
||||||
InvenTreeOutputOption('sub_part_detail'),
|
InvenTreeOutputOption('sub_part_detail'),
|
||||||
|
InvenTreeOutputOption('substitutes'),
|
||||||
|
InvenTreeOutputOption('pricing'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1563,7 +1563,15 @@ class BomItemSerializer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
substitutes = enable_filter(
|
substitutes = enable_filter(
|
||||||
BomItemSubstituteSerializer(many=True, read_only=True, allow_null=True), True
|
BomItemSubstituteSerializer(many=True, read_only=True, allow_null=True),
|
||||||
|
False,
|
||||||
|
filter_name='substitutes',
|
||||||
|
prefetch_fields=[
|
||||||
|
'substitutes',
|
||||||
|
'substitutes__part',
|
||||||
|
'substitutes__part__stock_items',
|
||||||
|
'substitutes__part__pricing_data',
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
part_detail = enable_filter(
|
part_detail = enable_filter(
|
||||||
@@ -1684,9 +1692,7 @@ class BomItemSerializer(
|
|||||||
'sub_part__stock_items',
|
'sub_part__stock_items',
|
||||||
'sub_part__stock_items__allocations',
|
'sub_part__stock_items__allocations',
|
||||||
'sub_part__stock_items__sales_order_allocations',
|
'sub_part__stock_items__sales_order_allocations',
|
||||||
'substitutes',
|
)
|
||||||
'substitutes__part__stock_items',
|
|
||||||
).select_related('part__pricing_data', 'sub_part__pricing_data')
|
|
||||||
|
|
||||||
# Annotate with the 'total pricing' information based on unit pricing and quantity
|
# Annotate with the 'total pricing' information based on unit pricing and quantity
|
||||||
queryset = queryset.annotate(
|
queryset = queryset.annotate(
|
||||||
@@ -1751,6 +1757,7 @@ class CategoryParameterTemplateSerializer(
|
|||||||
source='template', many=False, read_only=True
|
source='template', many=False, read_only=True
|
||||||
),
|
),
|
||||||
True,
|
True,
|
||||||
|
prefetch_fields=['template'],
|
||||||
)
|
)
|
||||||
|
|
||||||
category_detail = enable_filter(
|
category_detail = enable_filter(
|
||||||
@@ -1758,6 +1765,7 @@ class CategoryParameterTemplateSerializer(
|
|||||||
source='category', many=False, read_only=True, allow_null=True
|
source='category', many=False, read_only=True, allow_null=True
|
||||||
),
|
),
|
||||||
True,
|
True,
|
||||||
|
prefetch_fields=['category'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2708,7 +2708,7 @@ class BomItemTest(InvenTreeAPITestCase):
|
|||||||
"""Get the detail view for a single BomItem object."""
|
"""Get the detail view for a single BomItem object."""
|
||||||
url = reverse('api-bom-item-detail', kwargs={'pk': 3})
|
url = reverse('api-bom-item-detail', kwargs={'pk': 3})
|
||||||
|
|
||||||
response = self.get(url, expected_code=200)
|
response = self.get(url, {'substitutes': True}, expected_code=200)
|
||||||
|
|
||||||
expected_values = [
|
expected_values = [
|
||||||
'allow_variants',
|
'allow_variants',
|
||||||
@@ -2882,6 +2882,7 @@ class BomItemTest(InvenTreeAPITestCase):
|
|||||||
# The BomItem detail endpoint should now also reflect the substitute data
|
# The BomItem detail endpoint should now also reflect the substitute data
|
||||||
data = self.get(
|
data = self.get(
|
||||||
reverse('api-bom-item-detail', kwargs={'pk': bom_item.pk}),
|
reverse('api-bom-item-detail', kwargs={'pk': bom_item.pk}),
|
||||||
|
data={'substitutes': True},
|
||||||
expected_code=200,
|
expected_code=200,
|
||||||
).data
|
).data
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,8 @@ class StockItemTestResultSerializer(
|
|||||||
read_only_fields = ['pk', 'user', 'date']
|
read_only_fields = ['pk', 'user', 'date']
|
||||||
|
|
||||||
user_detail = enable_filter(
|
user_detail = enable_filter(
|
||||||
UserSerializer(source='user', read_only=True, allow_null=True)
|
UserSerializer(source='user', read_only=True, allow_null=True),
|
||||||
|
prefetch_fields=['user'],
|
||||||
)
|
)
|
||||||
|
|
||||||
template = serializers.PrimaryKeyRelatedField(
|
template = serializers.PrimaryKeyRelatedField(
|
||||||
@@ -238,7 +239,8 @@ class StockItemTestResultSerializer(
|
|||||||
template_detail = enable_filter(
|
template_detail = enable_filter(
|
||||||
part_serializers.PartTestTemplateSerializer(
|
part_serializers.PartTestTemplateSerializer(
|
||||||
source='template', read_only=True, allow_null=True
|
source='template', read_only=True, allow_null=True
|
||||||
)
|
),
|
||||||
|
prefetch_fields=['template'],
|
||||||
)
|
)
|
||||||
|
|
||||||
attachment = InvenTree.serializers.InvenTreeAttachmentSerializerField(
|
attachment = InvenTree.serializers.InvenTreeAttachmentSerializerField(
|
||||||
@@ -1244,11 +1246,13 @@ class StockTrackingSerializer(
|
|||||||
label = serializers.CharField(read_only=True)
|
label = serializers.CharField(read_only=True)
|
||||||
|
|
||||||
item_detail = enable_filter(
|
item_detail = enable_filter(
|
||||||
StockItemSerializer(source='item', many=False, read_only=True, allow_null=True)
|
StockItemSerializer(source='item', many=False, read_only=True, allow_null=True),
|
||||||
|
prefetch_fields=['item'],
|
||||||
)
|
)
|
||||||
|
|
||||||
user_detail = enable_filter(
|
user_detail = enable_filter(
|
||||||
UserSerializer(source='user', many=False, read_only=True, allow_null=True)
|
UserSerializer(source='user', many=False, read_only=True, allow_null=True),
|
||||||
|
prefetch_fields=['user'],
|
||||||
)
|
)
|
||||||
|
|
||||||
deltas = serializers.JSONField(read_only=True)
|
deltas = serializers.JSONField(read_only=True)
|
||||||
|
|||||||
@@ -291,13 +291,6 @@ class GroupMixin(SerializerContextMixin):
|
|||||||
serializer_class = GroupSerializer
|
serializer_class = GroupSerializer
|
||||||
permission_classes = [InvenTree.permissions.IsStaffOrReadOnlyScope]
|
permission_classes = [InvenTree.permissions.IsStaffOrReadOnlyScope]
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
"""Return queryset for this endpoint.
|
|
||||||
|
|
||||||
Note that the queryset is filtered by the permissions of the current user.
|
|
||||||
"""
|
|
||||||
return super().get_queryset().prefetch_related('rule_sets', 'user_set')
|
|
||||||
|
|
||||||
|
|
||||||
class GroupOutputOptions(OutputConfiguration):
|
class GroupOutputOptions(OutputConfiguration):
|
||||||
"""Holds all available output options for Group views."""
|
"""Holds all available output options for Group views."""
|
||||||
|
|||||||
@@ -268,11 +268,13 @@ class GroupSerializer(FilterableSerializerMixin, InvenTreeModelSerializer):
|
|||||||
source='rule_sets', many=True, read_only=True, allow_null=True
|
source='rule_sets', many=True, read_only=True, allow_null=True
|
||||||
),
|
),
|
||||||
filter_name='role_detail',
|
filter_name='role_detail',
|
||||||
|
prefetch_fields=['rule_sets'],
|
||||||
)
|
)
|
||||||
|
|
||||||
users = enable_filter(
|
users = enable_filter(
|
||||||
UserSerializer(source='user_set', many=True, read_only=True, allow_null=True),
|
UserSerializer(source='user_set', many=True, read_only=True, allow_null=True),
|
||||||
filter_name='user_detail',
|
filter_name='user_detail',
|
||||||
|
prefetch_fields=['user_set'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user