diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index 324e08988d..91e54fa77c 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,11 +1,16 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 430 +INVENTREE_API_VERSION = 431 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v431 -> 2025-12-14 : https://github.com/inventree/InvenTree/pull/11006 + - Remove duplicate "address" field on the Company API endpoint + - Make "primary_address" field optional on the Company API endpoint + - Remove "address_count" field from the Company API endpoint + v430 -> 2025-12-04 : https://github.com/inventree/InvenTree/pull/10699 - Removed the "PartParameter" and "PartParameterTemplate" API endpoints - Removed the "ManufacturerPartParameter" API endpoint diff --git a/src/backend/InvenTree/InvenTree/models.py b/src/backend/InvenTree/InvenTree/models.py index c3f5b42f93..978b11532c 100644 --- a/src/backend/InvenTree/InvenTree/models.py +++ b/src/backend/InvenTree/InvenTree/models.py @@ -537,7 +537,9 @@ class InvenTreeParameterMixin(InvenTreePermissionCheckMixin, models.Model): return queryset.prefetch_related( 'parameters_list', 'parameters_list__model_type', + 'parameters_list__updated_by', 'parameters_list__template', + 'parameters_list__template__model_type', ) @property @@ -547,8 +549,9 @@ class InvenTreeParameterMixin(InvenTreePermissionCheckMixin, models.Model): This will return pre-fetched data if available (i.e. in a serializer context). """ # Check the query cache for pre-fetched parameters - if 'parameters_list' in getattr(self, '_prefetched_objects_cache', {}): - return self._prefetched_objects_cache['parameters_list'] + if cache := getattr(self, '_prefetched_objects_cache', None): + if 'parameters_list' in cache: + return cache['parameters_list'] return self.parameters_list.all() diff --git a/src/backend/InvenTree/company/models.py b/src/backend/InvenTree/company/models.py index fbe8ccdd01..4e83275df7 100644 --- a/src/backend/InvenTree/company/models.py +++ b/src/backend/InvenTree/company/models.py @@ -238,8 +238,14 @@ class Company( @property def primary_address(self): - """Returns address object of primary address. Parsed by serializer.""" - return Address.objects.filter(company=self.id).filter(primary=True).first() + """Returns address object of primary address for this Company.""" + # We may have a pre-fetched primary address list + if hasattr(self, 'primary_address_list'): + addresses = self.primary_address_list + return addresses[0] if len(addresses) > 0 else None + + # Otherwise, query the database + return self.addresses.filter(primary=True).first() @property def currency_code(self): diff --git a/src/backend/InvenTree/company/serializers.py b/src/backend/InvenTree/company/serializers.py index ba68d4a42b..67fbfe763e 100644 --- a/src/backend/InvenTree/company/serializers.py +++ b/src/backend/InvenTree/company/serializers.py @@ -6,7 +6,6 @@ from django.core.files.base import ContentFile from django.db.models import Prefetch from django.utils.translation import gettext_lazy as _ -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from sql_util.utils import SubqueryCount from taggit.serializers import TagListSerializerField @@ -136,7 +135,6 @@ class CompanySerializer( 'website', 'name', 'phone', - 'address', 'email', 'currency', 'contact', @@ -150,7 +148,6 @@ class CompanySerializer( 'parts_supplied', 'parts_manufactured', 'remote_image', - 'address_count', 'primary_address', 'tax_id', 'parameters', @@ -166,8 +163,6 @@ class CompanySerializer( queryset = queryset.annotate(parts_supplied=SubqueryCount('supplied_parts')) - queryset = queryset.annotate(address_count=SubqueryCount('addresses')) - queryset = queryset.prefetch_related( Prefetch( 'addresses', @@ -180,30 +175,12 @@ class CompanySerializer( return queryset - address = serializers.SerializerMethodField( - label=_('Primary Address'), - help_text=_( - 'Return the string representation for the primary address. This property exists for backwards compatibility.' - ), - allow_null=True, + primary_address = enable_filter( + AddressBriefSerializer(read_only=True, allow_null=True), + True, + filter_name='address_detail', ) - primary_address = serializers.SerializerMethodField(allow_null=True) - - @extend_schema_field(serializers.CharField()) - def get_address(self, obj): - """Return string version of primary address (for backwards compatibility).""" - if hasattr(obj, 'primary_address_list') and obj.primary_address_list: - return str(obj.primary_address_list[0]) - return None - - @extend_schema_field(AddressSerializer()) - def get_primary_address(self, obj): - """Return full address object for primary address using prefetch data.""" - if hasattr(obj, 'primary_address_list') and obj.primary_address_list: - return AddressSerializer(obj.primary_address_list[0]).data - return None - image = InvenTreeImageSerializerField(required=False, allow_null=True) email = serializers.EmailField( @@ -211,8 +188,8 @@ class CompanySerializer( ) parts_supplied = serializers.IntegerField(read_only=True) + parts_manufactured = serializers.IntegerField(read_only=True) - address_count = serializers.IntegerField(read_only=True) currency = InvenTreeCurrencySerializer( help_text=_('Default currency used for this supplier'), required=True diff --git a/src/backend/InvenTree/part/test_api.py b/src/backend/InvenTree/part/test_api.py index fb70ed442b..2deb287f08 100644 --- a/src/backend/InvenTree/part/test_api.py +++ b/src/backend/InvenTree/part/test_api.py @@ -2065,8 +2065,8 @@ class PartListTests(PartAPITestBase): if b and result['category'] is not None: self.assertIn('category_detail', result) - # No more than 22 DB queries - self.assertLessEqual(len(ctx), 22) + # No more than 25 DB queries + self.assertLessEqual(len(ctx), 25) def test_price_breaks(self): """Test that price_breaks parameter works correctly and efficiently."""