From dc1acfdacb8cd5e45034ba89d2be1532cd7b9f1b Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Thu, 10 Apr 2025 01:09:52 +0200 Subject: [PATCH] refactor(backend): metadata endpoint (#9488) * refactor(backend): simplify metadata endpoint * fix imports * simplify even more * remove unneeded schema tooling * fix attr handling --- src/backend/InvenTree/InvenTree/api.py | 39 +++++++++++--------------- src/backend/InvenTree/build/api.py | 6 ++-- src/backend/InvenTree/common/api.py | 6 ++-- src/backend/InvenTree/company/api.py | 12 +++----- src/backend/InvenTree/order/api.py | 30 +++++++------------- src/backend/InvenTree/part/api.py | 31 ++++++++------------ src/backend/InvenTree/plugin/api.py | 5 ++-- src/backend/InvenTree/report/api.py | 6 ++-- src/backend/InvenTree/stock/api.py | 12 +++----- 9 files changed, 54 insertions(+), 93 deletions(-) diff --git a/src/backend/InvenTree/InvenTree/api.py b/src/backend/InvenTree/InvenTree/api.py index 8a0f4e0f68..5e5155232c 100644 --- a/src/backend/InvenTree/InvenTree/api.py +++ b/src/backend/InvenTree/InvenTree/api.py @@ -1,7 +1,6 @@ """Main JSON interface views.""" import json -import sys from pathlib import Path from django.conf import settings @@ -18,15 +17,14 @@ from rest_framework.response import Response from rest_framework.serializers import ValidationError from rest_framework.views import APIView -import common.models +import InvenTree.ready import InvenTree.version import users.models from common.settings import get_global_setting -from InvenTree import helpers, ready +from InvenTree import helpers from InvenTree.auth_overrides import registration_enabled from InvenTree.mixins import ListCreateAPI from InvenTree.sso import sso_registration_enabled -from part.models import Part from plugin.serializers import MetadataSerializer from users.models import ApiToken @@ -707,37 +705,32 @@ class APISearchView(GenericAPIView): class MetadataView(RetrieveUpdateAPI): """Generic API endpoint for reading and editing metadata for a model.""" - MODEL_REF = 'model' - - def get_model_type(self): - """Return the model type associated with this API instance.""" - model = self.kwargs.get(self.MODEL_REF, None) - - if ready.isGeneratingSchema(): - model = common.models.ProjectCode - - if 'lookup_field' in self.kwargs: - # Set custom lookup field (instead of default 'pk' value) if supplied - self.lookup_field = self.kwargs.pop('lookup_field') + model = None # Placeholder for the model class + @classmethod + def as_view(cls, model, lookup_field=None, **initkwargs): + """Override to ensure model specific rendering.""" if model is None: raise ValidationError( - f"MetadataView called without '{self.MODEL_REF}' parameter" + "MetadataView defined without 'model' arg" ) # pragma: no cover + initkwargs['model'] = model - return model + # Set custom lookup field (instead of default 'pk' value) if supplied + if lookup_field: + initkwargs['lookup_field'] = lookup_field + + return super().as_view(**initkwargs) def get_permission_model(self): """Return the 'permission' model associated with this view.""" - return self.get_model_type() + return self.model def get_queryset(self): """Return the queryset for this endpoint.""" - return self.get_model_type().objects.all() + return self.model.objects.all() def get_serializer(self, *args, **kwargs): """Return MetadataSerializer instance.""" # Detect if we are currently generating the OpenAPI schema - if 'spectacular' in sys.argv: - return MetadataSerializer(Part, *args, **kwargs) # pragma: no cover - return MetadataSerializer(self.get_model_type(), *args, **kwargs) + return MetadataSerializer(self.model, *args, **kwargs) diff --git a/src/backend/InvenTree/build/api.py b/src/backend/InvenTree/build/api.py index 0720407fd0..1b017d73dc 100644 --- a/src/backend/InvenTree/build/api.py +++ b/src/backend/InvenTree/build/api.py @@ -920,8 +920,7 @@ build_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': BuildItem}, + MetadataView.as_view(model=BuildItem), name='api-build-item-metadata', ), path('', BuildItemDetail.as_view(), name='api-build-item-detail'), @@ -967,8 +966,7 @@ build_api_urls = [ path('unallocate/', BuildUnallocate.as_view(), name='api-build-unallocate'), path( 'metadata/', - MetadataView.as_view(), - {'model': Build}, + MetadataView.as_view(model=Build), name='api-build-metadata', ), path('', BuildDetail.as_view(), name='api-build-detail'), diff --git a/src/backend/InvenTree/common/api.py b/src/backend/InvenTree/common/api.py index 2ff69b8584..4a696a755d 100644 --- a/src/backend/InvenTree/common/api.py +++ b/src/backend/InvenTree/common/api.py @@ -986,8 +986,7 @@ common_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': common.models.Attachment}, + MetadataView.as_view(model=common.models.Attachment), name='api-attachment-metadata', ), path('', AttachmentDetail.as_view(), name='api-attachment-detail'), @@ -1012,8 +1011,7 @@ common_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': common.models.ProjectCode}, + MetadataView.as_view(model=common.models.ProjectCode), name='api-project-code-metadata', ), path( diff --git a/src/backend/InvenTree/company/api.py b/src/backend/InvenTree/company/api.py index 97c04117dd..d4ba2c0990 100644 --- a/src/backend/InvenTree/company/api.py +++ b/src/backend/InvenTree/company/api.py @@ -516,8 +516,7 @@ manufacturer_part_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': ManufacturerPart}, + MetadataView.as_view(model=ManufacturerPart), name='api-manufacturer-part-metadata', ), path( @@ -538,8 +537,7 @@ supplier_part_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': SupplierPart}, + MetadataView.as_view(model=SupplierPart), name='api-supplier-part-metadata', ), path('', SupplierPartDetail.as_view(), name='api-supplier-part-detail'), @@ -574,8 +572,7 @@ company_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': Company}, + MetadataView.as_view(model=Company), name='api-company-metadata', ), path('', CompanyDetail.as_view(), name='api-company-detail'), @@ -589,8 +586,7 @@ company_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': Contact}, + MetadataView.as_view(model=Contact), name='api-contact-metadata', ), path('', ContactDetail.as_view(), name='api-contact-detail'), diff --git a/src/backend/InvenTree/order/api.py b/src/backend/InvenTree/order/api.py index f09a04e0e2..283e616cd9 100644 --- a/src/backend/InvenTree/order/api.py +++ b/src/backend/InvenTree/order/api.py @@ -1779,8 +1779,7 @@ order_api_urls = [ path('issue/', PurchaseOrderIssue.as_view(), name='api-po-issue'), path( 'metadata/', - MetadataView.as_view(), - {'model': models.PurchaseOrder}, + MetadataView.as_view(model=models.PurchaseOrder), name='api-po-metadata', ), path( @@ -1812,8 +1811,7 @@ order_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': models.PurchaseOrderLineItem}, + MetadataView.as_view(model=models.PurchaseOrderLineItem), name='api-po-line-metadata', ), path( @@ -1835,8 +1833,7 @@ order_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': models.PurchaseOrderExtraLine}, + MetadataView.as_view(model=models.PurchaseOrderExtraLine), name='api-po-extra-line-metadata', ), path( @@ -1868,8 +1865,7 @@ order_api_urls = [ ), path( 'metadata/', - MetadataView.as_view(), - {'model': models.SalesOrderShipment}, + MetadataView.as_view(model=models.SalesOrderShipment), name='api-so-shipment-metadata', ), path( @@ -1910,8 +1906,7 @@ order_api_urls = [ ), path( 'metadata/', - MetadataView.as_view(), - {'model': models.SalesOrder}, + MetadataView.as_view(model=models.SalesOrder), name='api-so-metadata', ), # SalesOrder detail endpoint @@ -1938,8 +1933,7 @@ order_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': models.SalesOrderLineItem}, + MetadataView.as_view(model=models.SalesOrderLineItem), name='api-so-line-metadata', ), path( @@ -1961,8 +1955,7 @@ order_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': models.SalesOrderExtraLine}, + MetadataView.as_view(model=models.SalesOrderExtraLine), name='api-so-extra-line-metadata', ), path( @@ -2018,8 +2011,7 @@ order_api_urls = [ ), path( 'metadata/', - MetadataView.as_view(), - {'model': models.ReturnOrder}, + MetadataView.as_view(model=models.ReturnOrder), name='api-return-order-metadata', ), path( @@ -2047,8 +2039,7 @@ order_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': models.ReturnOrderLineItem}, + MetadataView.as_view(model=models.ReturnOrderLineItem), name='api-return-order-line-metadata', ), path( @@ -2079,8 +2070,7 @@ order_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': models.ReturnOrderExtraLine}, + MetadataView.as_view(model=models.ReturnOrderExtraLine), name='api-return-order-extra-line-metadata', ), path( diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py index 0243d94777..c5aed3b538 100644 --- a/src/backend/InvenTree/part/api.py +++ b/src/backend/InvenTree/part/api.py @@ -1996,8 +1996,9 @@ part_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': PartCategoryParameterTemplate}, + MetadataView.as_view( + model=PartCategoryParameterTemplate + ), name='api-part-category-parameter-metadata', ), path( @@ -2020,8 +2021,7 @@ part_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': PartCategory}, + MetadataView.as_view(model=PartCategory), name='api-part-category-metadata', ), # PartCategory detail endpoint @@ -2040,8 +2040,7 @@ part_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': PartTestTemplate}, + MetadataView.as_view(model=PartTestTemplate), name='api-part-test-template-metadata', ), path( @@ -2091,8 +2090,7 @@ part_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': PartRelated}, + MetadataView.as_view(model=PartRelated), name='api-part-related-metadata', ), path( @@ -2115,8 +2113,7 @@ part_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': PartParameterTemplate}, + MetadataView.as_view(model=PartParameterTemplate), name='api-part-parameter-template-metadata', ), path( @@ -2138,8 +2135,7 @@ part_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': PartParameter}, + MetadataView.as_view(model=PartParameter), name='api-part-parameter-metadata', ), path( @@ -2217,10 +2213,7 @@ part_api_urls = [ ), # Part metadata path( - 'metadata/', - MetadataView.as_view(), - {'model': Part}, - name='api-part-metadata', + 'metadata/', MetadataView.as_view(model=Part), name='api-part-metadata' ), # Part pricing path('pricing/', PartPricingDetail.as_view(), name='api-part-pricing'), @@ -2241,8 +2234,7 @@ bom_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': BomItemSubstitute}, + MetadataView.as_view(model=BomItemSubstitute), name='api-bom-substitute-metadata', ), path( @@ -2263,8 +2255,7 @@ bom_api_urls = [ path('validate/', BomItemValidate.as_view(), name='api-bom-item-validate'), path( 'metadata/', - MetadataView.as_view(), - {'model': BomItem}, + MetadataView.as_view(model=BomItem), name='api-bom-item-metadata', ), path('', BomDetail.as_view(), name='api-bom-item-detail'), diff --git a/src/backend/InvenTree/plugin/api.py b/src/backend/InvenTree/plugin/api.py index 896ef7cb1a..453c4f5885 100644 --- a/src/backend/InvenTree/plugin/api.py +++ b/src/backend/InvenTree/plugin/api.py @@ -502,8 +502,9 @@ plugin_api_urls = [ ), path( 'metadata/', - PluginMetadataView.as_view(), - {'model': PluginConfig, 'lookup_field': 'key'}, + PluginMetadataView.as_view( + model=PluginConfig, lookup_field='key' + ), name='api-plugin-metadata', ), path( diff --git a/src/backend/InvenTree/report/api.py b/src/backend/InvenTree/report/api.py index c40a663f9f..298c72fb95 100644 --- a/src/backend/InvenTree/report/api.py +++ b/src/backend/InvenTree/report/api.py @@ -362,8 +362,7 @@ label_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': report.models.LabelTemplate}, + MetadataView.as_view(model=report.models.LabelTemplate), name='api-label-template-metadata', ), path( @@ -390,8 +389,7 @@ report_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': report.models.ReportTemplate}, + MetadataView.as_view(model=report.models.ReportTemplate), name='api-report-template-metadata', ), path( diff --git a/src/backend/InvenTree/stock/api.py b/src/backend/InvenTree/stock/api.py index f298996779..f4119210ee 100644 --- a/src/backend/InvenTree/stock/api.py +++ b/src/backend/InvenTree/stock/api.py @@ -1511,8 +1511,7 @@ stock_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': StockLocation}, + MetadataView.as_view(model=StockLocation), name='api-location-metadata', ), path('', StockLocationDetail.as_view(), name='api-location-detail'), @@ -1530,8 +1529,7 @@ stock_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': StockLocationType}, + MetadataView.as_view(model=StockLocationType), name='api-location-type-metadata', ), path( @@ -1561,8 +1559,7 @@ stock_api_urls = [ include([ path( 'metadata/', - MetadataView.as_view(), - {'model': StockItemTestResult}, + MetadataView.as_view(model=StockItemTestResult), name='api-stock-test-result-metadata', ), path( @@ -1604,8 +1601,7 @@ stock_api_urls = [ path('install/', StockItemInstall.as_view(), name='api-stock-item-install'), path( 'metadata/', - MetadataView.as_view(), - {'model': StockItem}, + MetadataView.as_view(model=StockItem), name='api-stock-item-metadata', ), path('return/', StockItemReturn.as_view(), name='api-stock-item-return'),