From 0d27abc6fc22a8d40183a59eceef5dda57e99eae Mon Sep 17 00:00:00 2001 From: John Anderson Date: Fri, 6 Nov 2020 16:47:07 -0500 Subject: [PATCH] fixes #5314 - Fix config context rendering when multiple tags are assgined to an object --- docs/release-notes/version-2.9.md | 1 + netbox/extras/querysets.py | 4 ++-- netbox/extras/tests/test_models.py | 35 ++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index 042f75691..ce7289da4 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -10,6 +10,7 @@ ### Bug Fixes * [#5271](https://github.com/netbox-community/netbox/issues/5271) - Fix auto-population of region field when editing a device +* [#5314](https://github.com/netbox-community/netbox/issues/5314) - Fix config context rendering when multiple tags are assgined to an object --- diff --git a/netbox/extras/querysets.py b/netbox/extras/querysets.py index 9bfa5da83..92402c45f 100644 --- a/netbox/extras/querysets.py +++ b/netbox/extras/querysets.py @@ -60,7 +60,7 @@ class ConfigContextQuerySet(RestrictedQuerySet): Q(tenants=obj.tenant) | Q(tenants=None), Q(tags__slug__in=obj.tags.slugs()) | Q(tags=None), is_active=True, - ).order_by('weight', 'name') + ).order_by('weight', 'name').distinct() if aggregate_data: return queryset.aggregate( @@ -95,7 +95,7 @@ class ConfigContextModelQuerySet(RestrictedQuerySet): _data=EmptyGroupByJSONBAgg('data', ordering=['weight', 'name']) ).values("_data") ) - ) + ).distinct() def _get_config_context_filters(self): # Construct the set of Q objects for the specific object types diff --git a/netbox/extras/tests/test_models.py b/netbox/extras/tests/test_models.py index 280da75b6..80beb0296 100644 --- a/netbox/extras/tests/test_models.py +++ b/netbox/extras/tests/test_models.py @@ -75,6 +75,7 @@ class ConfigContextTest(TestCase): self.tenantgroup = TenantGroup.objects.create(name="Tenant Group") self.tenant = Tenant.objects.create(name="Tenant", group=self.tenantgroup) self.tag = Tag.objects.create(name="Tag", slug="tag") + self.tag2 = Tag.objects.create(name="Tag2", slug="tag2") self.device = Device.objects.create( name='Device 1', @@ -328,3 +329,37 @@ class ConfigContextTest(TestCase): annotated_queryset = VirtualMachine.objects.filter(name=virtual_machine.name).annotate_config_context_data() self.assertEqual(virtual_machine.get_config_context(), annotated_queryset[0].get_config_context()) + + def test_multiple_tags_return_distinct_objects(self): + """ + Tagged items use a generic relationship, which results in duplicate rows being returned when queried. + This is combatted by by appending distinct() to the config context querysets. This test creates a config + context assigned to two tags and ensures objects related by those same two tags result in only a single + config context record being returned. + + See https://github.com/netbox-community/netbox/issues/5314 + """ + tag_context = ConfigContext.objects.create( + name="tag", + weight=100, + data={ + "tag": 1 + } + ) + tag_context.tags.add(self.tag) + tag_context.tags.add(self.tag2) + + device = Device.objects.create( + name="Device 3", + site=self.site, + tenant=self.tenant, + platform=self.platform, + device_role=self.devicerole, + device_type=self.devicetype + ) + device.tags.add(self.tag) + device.tags.add(self.tag2) + + annotated_queryset = Device.objects.filter(name=device.name).annotate_config_context_data() + self.assertEqual(ConfigContext.objects.get_for_object(device).count(), 1) + self.assertEqual(device.get_config_context(), annotated_queryset[0].get_config_context())