diff --git a/netbox/dcim/api/serializers_/sites.py b/netbox/dcim/api/serializers_/sites.py index 21a020ca5..b818cd954 100644 --- a/netbox/dcim/api/serializers_/sites.py +++ b/netbox/dcim/api/serializers_/sites.py @@ -21,7 +21,7 @@ __all__ = ( class RegionSerializer(NestedGroupModelSerializer): parent = NestedRegionSerializer(required=False, allow_null=True, default=None) site_count = serializers.IntegerField(read_only=True, default=0) - prefix_count = RelatedObjectCountField('_prefixs') + prefix_count = RelatedObjectCountField('prefix_set') class Meta: model = Region @@ -35,7 +35,7 @@ class RegionSerializer(NestedGroupModelSerializer): class SiteGroupSerializer(NestedGroupModelSerializer): parent = NestedSiteGroupSerializer(required=False, allow_null=True, default=None) site_count = serializers.IntegerField(read_only=True, default=0) - prefix_count = RelatedObjectCountField('_prefixs') + prefix_count = RelatedObjectCountField('prefix_set') class Meta: model = SiteGroup @@ -63,7 +63,7 @@ class SiteSerializer(NetBoxModelSerializer): # Related object counts circuit_count = RelatedObjectCountField('circuit_terminations') device_count = RelatedObjectCountField('devices') - prefix_count = RelatedObjectCountField('_prefixs') + prefix_count = RelatedObjectCountField('prefix_set') rack_count = RelatedObjectCountField('racks') vlan_count = RelatedObjectCountField('vlans') virtualmachine_count = RelatedObjectCountField('virtual_machines') @@ -86,7 +86,7 @@ class LocationSerializer(NestedGroupModelSerializer): tenant = TenantSerializer(nested=True, required=False, allow_null=True) rack_count = serializers.IntegerField(read_only=True, default=0) device_count = serializers.IntegerField(read_only=True, default=0) - prefix_count = RelatedObjectCountField('_prefixs') + prefix_count = RelatedObjectCountField('prefix_set') class Meta: model = Location diff --git a/netbox/dcim/graphql/types.py b/netbox/dcim/graphql/types.py index 6493ec6b1..ff539cd64 100644 --- a/netbox/dcim/graphql/types.py +++ b/netbox/dcim/graphql/types.py @@ -465,7 +465,7 @@ class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, Organi @strawberry_django.field def clusters(self) -> List[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]]: - return self._clusters.all() + return self.cluster_set.all() @strawberry_django.field def circuit_terminations(self) -> List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]: @@ -716,7 +716,7 @@ class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): @strawberry_django.field def clusters(self) -> List[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]]: - return self._clusters.all() + return self.cluster_set.all() @strawberry_django.field def circuit_terminations(self) -> List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]: @@ -749,7 +749,7 @@ class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObje @strawberry_django.field def clusters(self) -> List[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]]: - return self._clusters.all() + return self.cluster_set.all() @strawberry_django.field def circuit_terminations(self) -> List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]: @@ -773,7 +773,7 @@ class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): @strawberry_django.field def clusters(self) -> List[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]]: - return self._clusters.all() + return self.cluster_set.all() @strawberry_django.field def circuit_terminations(self) -> List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]: diff --git a/netbox/dcim/models/mixins.py b/netbox/dcim/models/mixins.py index 1df3364c4..ac4d7dab9 100644 --- a/netbox/dcim/models/mixins.py +++ b/netbox/dcim/models/mixins.py @@ -59,28 +59,24 @@ class CachedScopeMixin(models.Model): _location = models.ForeignKey( to='dcim.Location', on_delete=models.CASCADE, - related_name='_%(class)ss', blank=True, null=True ) _site = models.ForeignKey( to='dcim.Site', on_delete=models.CASCADE, - related_name='_%(class)ss', blank=True, null=True ) _region = models.ForeignKey( to='dcim.Region', on_delete=models.CASCADE, - related_name='_%(class)ss', blank=True, null=True ) _site_group = models.ForeignKey( to='dcim.SiteGroup', on_delete=models.CASCADE, - related_name='_%(class)ss', blank=True, null=True ) diff --git a/netbox/ipam/migrations/0072_prefix_cached_relations.py b/netbox/ipam/migrations/0072_prefix_cached_relations.py index 5a49aa344..4b438f7d5 100644 --- a/netbox/ipam/migrations/0072_prefix_cached_relations.py +++ b/netbox/ipam/migrations/0072_prefix_cached_relations.py @@ -29,22 +29,22 @@ class Migration(migrations.Migration): migrations.AddField( model_name='prefix', name='_location', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='_%(class)ss', to='dcim.location'), + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location'), ), migrations.AddField( model_name='prefix', name='_region', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='_%(class)ss', to='dcim.region'), + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.region'), ), migrations.AddField( model_name='prefix', name='_site', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='_%(class)ss', to='dcim.site'), + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.site'), ), migrations.AddField( model_name='prefix', name='_site_group', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='_%(class)ss', to='dcim.sitegroup'), + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.sitegroup'), ), # Populate denormalized FK values diff --git a/netbox/utilities/api.py b/netbox/utilities/api.py index 11b914811..bee231fd5 100644 --- a/netbox/utilities/api.py +++ b/netbox/utilities/api.py @@ -129,8 +129,15 @@ def get_annotations_for_serializer(serializer_class, fields_to_include=None): for field_name, field in serializer_class._declared_fields.items(): if field_name in fields_to_include and type(field) is RelatedObjectCountField: - related_field = model._meta.get_field(field.relation).field - annotations[field_name] = count_related(related_field.model, related_field.name) + try: + related_field = model._meta.get_field(field.relation).field + related_field_name = related_field.name + except FieldDoesNotExist: + # Handle RelatedObjectCountField with no related_name given + related_field = getattr(model, field.relation).field + related_field_name = field_name + + annotations[field_name] = count_related(related_field.model, related_field_name) return annotations diff --git a/netbox/virtualization/migrations/0046_alter_cluster__location_alter_cluster__region_and_more.py b/netbox/virtualization/migrations/0046_alter_cluster__location_alter_cluster__region_and_more.py new file mode 100644 index 000000000..7b1168da0 --- /dev/null +++ b/netbox/virtualization/migrations/0046_alter_cluster__location_alter_cluster__region_and_more.py @@ -0,0 +1,41 @@ +# Generated by Django 5.0.9 on 2024-11-14 19:04 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0196_qinq_svlan'), + ('virtualization', '0045_clusters_cached_relations'), + ] + + operations = [ + migrations.AlterField( + model_name='cluster', + name='_location', + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location' + ), + ), + migrations.AlterField( + model_name='cluster', + name='_region', + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.region' + ), + ), + migrations.AlterField( + model_name='cluster', + name='_site', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.site'), + ), + migrations.AlterField( + model_name='cluster', + name='_site_group', + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.sitegroup' + ), + ), + ] diff --git a/netbox/wireless/migrations/0012_alter_wirelesslan__location_and_more.py b/netbox/wireless/migrations/0012_alter_wirelesslan__location_and_more.py new file mode 100644 index 000000000..7edaff92b --- /dev/null +++ b/netbox/wireless/migrations/0012_alter_wirelesslan__location_and_more.py @@ -0,0 +1,41 @@ +# Generated by Django 5.0.9 on 2024-11-14 19:04 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0196_qinq_svlan'), + ('wireless', '0011_wirelesslan__location_wirelesslan__region_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='wirelesslan', + name='_location', + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location' + ), + ), + migrations.AlterField( + model_name='wirelesslan', + name='_region', + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.region' + ), + ), + migrations.AlterField( + model_name='wirelesslan', + name='_site', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.site'), + ), + migrations.AlterField( + model_name='wirelesslan', + name='_site_group', + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.sitegroup' + ), + ), + ]