From e5def31ec527f66719c271ea4f2bd051d5054ab3 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sat, 28 Feb 2026 23:12:35 +0100 Subject: [PATCH] !refactor(backend): remove legacy metadata endpoints (#11111) * !refactor(backend): remove legacy metadata endpoints * add changelog * fix indent * remove legacy test --- CHANGELOG.md | 2 + src/backend/InvenTree/build/api.py | 11 +--- src/backend/InvenTree/common/api.py | 35 ++---------- src/backend/InvenTree/company/api.py | 38 +++---------- src/backend/InvenTree/order/api.py | 71 +++++-------------------- src/backend/InvenTree/part/api.py | 49 +++-------------- src/backend/InvenTree/report/api.py | 21 ++------ src/backend/InvenTree/stock/api.py | 34 +++--------- src/backend/InvenTree/stock/test_api.py | 52 ------------------ 9 files changed, 46 insertions(+), 267 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d27599a38f..ab386ea477 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking Changes - Remove deprecated features and APIs +- [#11111](https://github.com/inventree/InvenTree/pull/11111) - removes legacy metadata APIs - [#9814](https://github.com/inventree/InvenTree/pull/9814) - removes legacy config path support + ## Unreleased - YYYY-MM-DD ### Breaking Changes diff --git a/src/backend/InvenTree/build/api.py b/src/backend/InvenTree/build/api.py index b155602b50..a5c601e164 100644 --- a/src/backend/InvenTree/build/api.py +++ b/src/backend/InvenTree/build/api.py @@ -24,7 +24,7 @@ from build.models import Build, BuildItem, BuildLine from build.status_codes import BuildStatus, BuildStatusGroups from data_exporter.mixins import DataExportViewMixin from generic.states.api import StatusView -from InvenTree.api import BulkDeleteMixin, ParameterListMixin, meta_path +from InvenTree.api import BulkDeleteMixin, ParameterListMixin from InvenTree.fields import InvenTreeOutputOption, OutputConfiguration from InvenTree.filters import ( SEARCH_ORDER_FILTER_ALIAS, @@ -994,13 +994,7 @@ build_api_urls = [ path( 'item/', include([ - path( - '/', - include([ - meta_path(BuildItem), - path('', BuildItemDetail.as_view(), name='api-build-item-detail'), - ]), - ), + path('/', BuildItemDetail.as_view(), name='api-build-item-detail'), path('', BuildItemList.as_view(), name='api-build-item-list'), ]), ), @@ -1040,7 +1034,6 @@ build_api_urls = [ path('finish/', BuildFinish.as_view(), name='api-build-finish'), path('cancel/', BuildCancel.as_view(), name='api-build-cancel'), path('unallocate/', BuildUnallocate.as_view(), name='api-build-unallocate'), - meta_path(Build), 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 eccd885d98..923a24b485 100644 --- a/src/backend/InvenTree/common/api.py +++ b/src/backend/InvenTree/common/api.py @@ -46,7 +46,6 @@ from InvenTree.api import ( BulkDeleteMixin, GenericMetadataView, SimpleGenericMetadataView, - meta_path, ) from InvenTree.config import CONFIG_LOOKUPS from InvenTree.filters import ( @@ -1407,13 +1406,7 @@ common_api_urls = [ path( 'attachment/', include([ - path( - '/', - include([ - meta_path(common.models.Attachment), - path('', AttachmentDetail.as_view(), name='api-attachment-detail'), - ]), - ), + path('/', AttachmentDetail.as_view(), name='api-attachment-detail'), path('', AttachmentList.as_view(), name='api-attachment-list'), ]), ), @@ -1426,14 +1419,8 @@ common_api_urls = [ include([ path( '/', - include([ - meta_path(common.models.ParameterTemplate), - path( - '', - ParameterTemplateDetail.as_view(), - name='api-parameter-template-detail', - ), - ]), + ParameterTemplateDetail.as_view(), + name='api-parameter-template-detail', ), path( '', @@ -1442,13 +1429,7 @@ common_api_urls = [ ), ]), ), - path( - '/', - include([ - meta_path(common.models.Parameter), - path('', ParameterDetail.as_view(), name='api-parameter-detail'), - ]), - ), + path('/', ParameterDetail.as_view(), name='api-parameter-detail'), path('', ParameterList.as_view(), name='api-parameter-list'), ]), ), @@ -1480,13 +1461,7 @@ common_api_urls = [ 'project-code/', include([ path( - '/', - include([ - meta_path(common.models.ProjectCode), - path( - '', ProjectCodeDetail.as_view(), name='api-project-code-detail' - ), - ]), + '/', ProjectCodeDetail.as_view(), name='api-project-code-detail' ), path('', ProjectCodeList.as_view(), name='api-project-code-list'), ]), diff --git a/src/backend/InvenTree/company/api.py b/src/backend/InvenTree/company/api.py index 8c1fe8db05..a3611566f7 100644 --- a/src/backend/InvenTree/company/api.py +++ b/src/backend/InvenTree/company/api.py @@ -9,7 +9,7 @@ from django_filters.rest_framework.filterset import FilterSet import part.models from data_exporter.mixins import DataExportViewMixin -from InvenTree.api import ListCreateDestroyAPIView, ParameterListMixin, meta_path +from InvenTree.api import ListCreateDestroyAPIView, ParameterListMixin from InvenTree.fields import InvenTreeOutputOption, OutputConfiguration from InvenTree.filters import SEARCH_ORDER_FILTER, SEARCH_ORDER_FILTER_ALIAS from InvenTree.mixins import ( @@ -492,29 +492,15 @@ class SupplierPriceBreakDetail(SupplierPriceBreakMixin, RetrieveUpdateDestroyAPI manufacturer_part_api_urls = [ path( '/', - include([ - meta_path(ManufacturerPart), - path( - '', - ManufacturerPartDetail.as_view(), - name='api-manufacturer-part-detail', - ), - ]), + ManufacturerPartDetail.as_view(), + name='api-manufacturer-part-detail', ), - # Catch anything else path('', ManufacturerPartList.as_view(), name='api-manufacturer-part-list'), ] supplier_part_api_urls = [ - path( - '/', - include([ - meta_path(SupplierPart), - path('', SupplierPartDetail.as_view(), name='api-supplier-part-detail'), - ]), - ), - # Catch anything else + path('/', SupplierPartDetail.as_view(), name='api-supplier-part-detail'), path('', SupplierPartList.as_view(), name='api-supplier-part-list'), ] @@ -538,23 +524,11 @@ company_api_urls = [ ), ]), ), - path( - '/', - include([ - meta_path(Company), - path('', CompanyDetail.as_view(), name='api-company-detail'), - ]), - ), + path('/', CompanyDetail.as_view(), name='api-company-detail'), path( 'contact/', include([ - path( - '/', - include([ - meta_path(Contact), - path('', ContactDetail.as_view(), name='api-contact-detail'), - ]), - ), + path('/', ContactDetail.as_view(), name='api-contact-detail'), path('', ContactList.as_view(), name='api-contact-list'), ]), ), diff --git a/src/backend/InvenTree/order/api.py b/src/backend/InvenTree/order/api.py index 096e8d1dfb..854c8d906c 100644 --- a/src/backend/InvenTree/order/api.py +++ b/src/backend/InvenTree/order/api.py @@ -28,12 +28,7 @@ import stock.models as stock_models import stock.serializers as stock_serializers from data_exporter.mixins import DataExportViewMixin from generic.states.api import StatusView -from InvenTree.api import ( - BulkUpdateMixin, - ListCreateDestroyAPIView, - ParameterListMixin, - meta_path, -) +from InvenTree.api import BulkUpdateMixin, ListCreateDestroyAPIView, ParameterListMixin from InvenTree.fields import InvenTreeOutputOption, OutputConfiguration from InvenTree.filters import ( SEARCH_ORDER_FILTER, @@ -1903,7 +1898,6 @@ order_api_urls = [ name='api-po-complete', ), path('issue/', PurchaseOrderIssue.as_view(), name='api-po-issue'), - meta_path(models.PurchaseOrder), path( 'receive/', PurchaseOrderReceive.as_view(), @@ -1930,14 +1924,8 @@ order_api_urls = [ include([ path( '/', - include([ - meta_path(models.PurchaseOrderLineItem), - path( - '', - PurchaseOrderLineItemDetail.as_view(), - name='api-po-line-detail', - ), - ]), + PurchaseOrderLineItemDetail.as_view(), + name='api-po-line-detail', ), path('', PurchaseOrderLineItemList.as_view(), name='api-po-line-list'), ]), @@ -1948,14 +1936,8 @@ order_api_urls = [ include([ path( '/', - include([ - meta_path(models.PurchaseOrderExtraLine), - path( - '', - PurchaseOrderExtraLineDetail.as_view(), - name='api-po-extra-line-detail', - ), - ]), + PurchaseOrderExtraLineDetail.as_view(), + name='api-po-extra-line-detail', ), path( '', PurchaseOrderExtraLineList.as_view(), name='api-po-extra-line-list' @@ -1977,7 +1959,6 @@ order_api_urls = [ SalesOrderShipmentComplete.as_view(), name='api-so-shipment-ship', ), - meta_path(models.SalesOrderShipment), path( '', SalesOrderShipmentDetail.as_view(), @@ -2014,7 +1995,6 @@ order_api_urls = [ SalesOrderComplete.as_view(), name='api-so-complete', ), - meta_path(models.SalesOrder), # SalesOrder detail endpoint path('', SalesOrderDetail.as_view(), name='api-so-detail'), ]), @@ -2036,14 +2016,8 @@ order_api_urls = [ include([ path( '/', - include([ - meta_path(models.SalesOrderLineItem), - path( - '', - SalesOrderLineItemDetail.as_view(), - name='api-so-line-detail', - ), - ]), + SalesOrderLineItemDetail.as_view(), + name='api-so-line-detail', ), path('', SalesOrderLineItemList.as_view(), name='api-so-line-list'), ]), @@ -2054,14 +2028,8 @@ order_api_urls = [ include([ path( '/', - include([ - meta_path(models.SalesOrderExtraLine), - path( - '', - SalesOrderExtraLineDetail.as_view(), - name='api-so-extra-line-detail', - ), - ]), + SalesOrderExtraLineDetail.as_view(), + name='api-so-extra-line-detail', ), path('', SalesOrderExtraLineList.as_view(), name='api-so-extra-line-list'), ]), @@ -2107,7 +2075,6 @@ order_api_urls = [ ReturnOrderReceive.as_view(), name='api-return-order-receive', ), - meta_path(models.ReturnOrder), path( '', ReturnOrderDetail.as_view(), name='api-return-order-detail' ), @@ -2130,14 +2097,8 @@ order_api_urls = [ include([ path( '/', - include([ - meta_path(models.ReturnOrderLineItem), - path( - '', - ReturnOrderLineItemDetail.as_view(), - name='api-return-order-line-detail', - ), - ]), + ReturnOrderLineItemDetail.as_view(), + name='api-return-order-line-detail', ), # Return order line item status code information path( @@ -2157,14 +2118,8 @@ order_api_urls = [ include([ path( '/', - include([ - meta_path(models.ReturnOrderExtraLine), - path( - '', - ReturnOrderExtraLineDetail.as_view(), - name='api-return-order-extra-line-detail', - ), - ]), + ReturnOrderExtraLineDetail.as_view(), + name='api-return-order-extra-line-detail', ), path( '', diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py index db8eefd5e6..3d03cfa9a9 100644 --- a/src/backend/InvenTree/part/api.py +++ b/src/backend/InvenTree/part/api.py @@ -19,7 +19,6 @@ from InvenTree.api import ( BulkUpdateMixin, ListCreateDestroyAPIView, ParameterListMixin, - meta_path, ) from InvenTree.fields import InvenTreeOutputOption, OutputConfiguration from InvenTree.filters import ( @@ -1563,14 +1562,8 @@ part_api_urls = [ include([ path( '/', - include([ - meta_path(PartCategoryParameterTemplate), - path( - '', - CategoryParameterDetail.as_view(), - name='api-part-category-parameter-detail', - ), - ]), + CategoryParameterDetail.as_view(), + name='api-part-category-parameter-detail', ), path( '', @@ -1581,12 +1574,7 @@ part_api_urls = [ ), # Category detail endpoints path( - '/', - include([ - meta_path(PartCategory), - # PartCategory detail endpoint - path('', CategoryDetail.as_view(), name='api-part-category-detail'), - ]), + '/', CategoryDetail.as_view(), name='api-part-category-detail' ), path('', CategoryList.as_view(), name='api-part-category-list'), ]), @@ -1597,14 +1585,8 @@ part_api_urls = [ include([ path( '/', - include([ - meta_path(PartTestTemplate), - path( - '', - PartTestTemplateDetail.as_view(), - name='api-part-test-template-detail', - ), - ]), + PartTestTemplateDetail.as_view(), + name='api-part-test-template-detail', ), path( '', PartTestTemplateList.as_view(), name='api-part-test-template-list' @@ -1642,13 +1624,7 @@ part_api_urls = [ 'related/', include([ path( - '/', - include([ - meta_path(PartRelated), - path( - '', PartRelatedDetail.as_view(), name='api-part-related-detail' - ), - ]), + '/', PartRelatedDetail.as_view(), name='api-part-related-detail' ), path('', PartRelatedList.as_view(), name='api-part-related-list'), ]), @@ -1699,8 +1675,6 @@ part_api_urls = [ path( 'bom-validate/', PartValidateBOM.as_view(), name='api-part-bom-validate' ), - # Part metadata - meta_path(Part), # Part pricing path('pricing/', PartPricingDetail.as_view(), name='api-part-pricing'), # Part detail endpoint @@ -1717,14 +1691,8 @@ bom_api_urls = [ # Detail view path( '/', - include([ - meta_path(BomItemSubstitute), - path( - '', - BomItemSubstituteDetail.as_view(), - name='api-bom-substitute-detail', - ), - ]), + BomItemSubstituteDetail.as_view(), + name='api-bom-substitute-detail', ), # Catch all path('', BomItemSubstituteList.as_view(), name='api-bom-substitute-list'), @@ -1735,7 +1703,6 @@ bom_api_urls = [ '/', include([ path('validate/', BomItemValidate.as_view(), name='api-bom-item-validate'), - meta_path(BomItem), path('', BomDetail.as_view(), name='api-bom-item-detail'), ]), ), diff --git a/src/backend/InvenTree/report/api.py b/src/backend/InvenTree/report/api.py index a02bfe74ae..d9ad6ab1cb 100644 --- a/src/backend/InvenTree/report/api.py +++ b/src/backend/InvenTree/report/api.py @@ -18,7 +18,6 @@ import report.models import report.serializers from common.models import DataOutput from common.serializers import DataOutputSerializer -from InvenTree.api import meta_path from InvenTree.filters import InvenTreeSearchFilter from InvenTree.mixins import ListCreateAPI, RetrieveUpdateDestroyAPI from plugin import PluginMixinEnum @@ -355,14 +354,8 @@ label_api_urls = [ include([ path( '/', - include([ - meta_path(report.models.LabelTemplate), - path( - '', - LabelTemplateDetail.as_view(), - name='api-label-template-detail', - ), - ]), + LabelTemplateDetail.as_view(), + name='api-label-template-detail', ), path('', LabelTemplateList.as_view(), name='api-label-template-list'), ]), @@ -378,14 +371,8 @@ report_api_urls = [ include([ path( '/', - include([ - meta_path(report.models.ReportTemplate), - path( - '', - ReportTemplateDetail.as_view(), - name='api-report-template-detail', - ), - ]), + ReportTemplateDetail.as_view(), + name='api-report-template-detail', ), path('', ReportTemplateList.as_view(), name='api-report-template-list'), ]), diff --git a/src/backend/InvenTree/stock/api.py b/src/backend/InvenTree/stock/api.py index 9b2fd32a3b..fcf800d45a 100644 --- a/src/backend/InvenTree/stock/api.py +++ b/src/backend/InvenTree/stock/api.py @@ -29,12 +29,7 @@ from company.models import Company, ManufacturerPart, SupplierPart from company.serializers import CompanySerializer from data_exporter.mixins import DataExportViewMixin from generic.states.api import StatusView -from InvenTree.api import ( - BulkCreateMixin, - BulkUpdateMixin, - ListCreateDestroyAPIView, - meta_path, -) +from InvenTree.api import BulkCreateMixin, BulkUpdateMixin, ListCreateDestroyAPIView from InvenTree.fields import InvenTreeOutputOption, OutputConfiguration from InvenTree.filters import ( ORDER_FILTER_ALIAS, @@ -1666,11 +1661,7 @@ stock_api_urls = [ path('tree/', StockLocationTree.as_view(), name='api-location-tree'), # Stock location detail endpoints path( - '/', - include([ - meta_path(StockLocation), - path('', StockLocationDetail.as_view(), name='api-location-detail'), - ]), + '/', StockLocationDetail.as_view(), name='api-location-detail' ), path('', StockLocationList.as_view(), name='api-location-list'), ]), @@ -1681,14 +1672,8 @@ stock_api_urls = [ include([ path( '/', - include([ - meta_path(StockLocationType), - path( - '', - StockLocationTypeDetail.as_view(), - name='api-location-type-detail', - ), - ]), + StockLocationTypeDetail.as_view(), + name='api-location-type-detail', ), path('', StockLocationTypeList.as_view(), name='api-location-type-list'), ]), @@ -1708,14 +1693,8 @@ stock_api_urls = [ include([ path( '/', - include([ - meta_path(StockItemTestResult), - path( - '', - StockItemTestResultDetail.as_view(), - name='api-stock-test-result-detail', - ), - ]), + StockItemTestResultDetail.as_view(), + name='api-stock-test-result-detail', ), path( '', StockItemTestResultList.as_view(), name='api-stock-test-result-list' @@ -1747,7 +1726,6 @@ stock_api_urls = [ include([ path('convert/', StockItemConvert.as_view(), name='api-stock-item-convert'), path('install/', StockItemInstall.as_view(), name='api-stock-item-install'), - meta_path(StockItem), path( 'serialize/', StockItemSerialize.as_view(), diff --git a/src/backend/InvenTree/stock/test_api.py b/src/backend/InvenTree/stock/test_api.py index 405f90a6b8..f23524eddf 100644 --- a/src/backend/InvenTree/stock/test_api.py +++ b/src/backend/InvenTree/stock/test_api.py @@ -2683,58 +2683,6 @@ class StockMergeTest(StockAPITestCase): self.assertEqual(StockItem.objects.filter(part=self.part).count(), n - 2) -class StockMetadataAPITest(InvenTreeAPITestCase): - """Unit tests for the various metadata endpoints of API.""" - - fixtures = [ - 'category', - 'part', - 'test_templates', - 'bom', - 'company', - 'location', - 'supplier_part', - 'stock', - 'stock_tests', - ] - - roles = ['stock.change', 'stock_location.change'] - - def metatester(self, raw_url: str, model): - """Generic tester.""" - modeldata = model.objects.first() - - # Useless test unless a model object is found - self.assertIsNotNone(modeldata) - - url = raw_url.format(pk=modeldata.pk) - - # Metadata is initially null - self.assertIsNone(modeldata.metadata) - - numstr = f'12{len(raw_url)}' - target_key = f'abc-{numstr}' - target_value = f'xyz-{raw_url}-{numstr}' - - # Create / update metadata entry (first try via old addresses) - data = {'metadata': {target_key: target_value}} - rsp = self.patch(url, data, expected_code=301) - self.patch(rsp.url, data, expected_code=200) - - # Refresh and check that metadata has been updated - modeldata.refresh_from_db() - self.assertEqual(modeldata.get_metadata(target_key), target_value) - - def test_metadata(self): - """Test all endpoints.""" - for raw_url, model in { - '/api/stock/location/{pk}/metadata/': StockLocation, - '/api/stock/test/{pk}/metadata/': StockItemTestResult, - '/api/stock/{pk}/metadata/': StockItem, - }.items(): - self.metatester(raw_url, model) - - class StockApiPerformanceTest(StockAPITestCase, InvenTreeAPIPerformanceTestCase): """Performance tests for the Stock API."""