diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index 5d0d72484..6872bab72 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -173,12 +173,18 @@ class ConfigContextSerializer(ValidatedModelSerializer): required=False, many=True ) + tags = SerializedPKRelatedField( + queryset=Tag.objects.all(), + serializer=TagSerializer, + required=False, + many=True + ) class Meta: model = ConfigContext fields = [ 'id', 'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms', - 'tenant_groups', 'tenants', 'data', + 'tenant_groups', 'tenants', 'tags', 'data', ] diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index b9bc013d1..52b2776b2 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -180,6 +180,17 @@ class ConfigContextFilter(django_filters.FilterSet): to_field_name='slug', label='Tenant (slug)', ) + tag_id = django_filters.ModelMultipleChoiceFilter( + field_name='tags', + queryset=Tag.objects.all(), + label='Tag', + ) + tag = django_filters.ModelMultipleChoiceFilter( + field_name='tags__slug', + queryset=Tag.objects.all(), + to_field_name='slug', + label='Tag (slug)', + ) class Meta: model = ConfigContext diff --git a/netbox/extras/forms.py b/netbox/extras/forms.py index b9f2d1538..2c1201dee 100644 --- a/netbox/extras/forms.py +++ b/netbox/extras/forms.py @@ -246,7 +246,7 @@ class ConfigContextForm(BootstrapMixin, forms.ModelForm): model = ConfigContext fields = [ 'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms', 'tenant_groups', - 'tenants', 'data', + 'tenants', 'tags', 'data', ] widgets = { 'regions': APISelectMultiple( @@ -266,6 +266,9 @@ class ConfigContextForm(BootstrapMixin, forms.ModelForm): ), 'tenants': APISelectMultiple( api_url="/api/tenancy/tenants/" + ), + 'tags': APISelectMultiple( + api_url="/api/extras/tags/" ) } @@ -347,6 +350,14 @@ class ConfigContextFilterForm(BootstrapMixin, forms.Form): value_field="slug", ) ) + tag = FilterChoiceField( + queryset=Tag.objects.all(), + to_field_name='slug', + widget=APISelectMultiple( + api_url="/api/extras/tags/", + value_field="slug", + ) + ) # diff --git a/netbox/extras/migrations/0034_configcontext_tags.py b/netbox/extras/migrations/0034_configcontext_tags.py new file mode 100644 index 000000000..363572535 --- /dev/null +++ b/netbox/extras/migrations/0034_configcontext_tags.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2019-12-11 09:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0033_graph_type_to_fk'), + ] + + operations = [ + migrations.AddField( + model_name='configcontext', + name='tags', + field=models.ManyToManyField(blank=True, related_name='_configcontext_tags_+', to='extras.Tag'), + ), + ] diff --git a/netbox/extras/models.py b/netbox/extras/models.py index 52dea8674..1f31a7670 100644 --- a/netbox/extras/models.py +++ b/netbox/extras/models.py @@ -673,6 +673,11 @@ class ConfigContext(models.Model): related_name='+', blank=True ) + tags = models.ManyToManyField( + to='extras.Tag', + related_name='+', + blank=True + ) data = JSONField() objects = ConfigContextQuerySet.as_manager() diff --git a/netbox/extras/querysets.py b/netbox/extras/querysets.py index 70c93968f..10d23d15e 100644 --- a/netbox/extras/querysets.py +++ b/netbox/extras/querysets.py @@ -39,6 +39,8 @@ class ConfigContextQuerySet(QuerySet): else: regions = [] + tags = obj.tags.slugs() + return self.filter( Q(regions__in=regions) | Q(regions=None), Q(sites=obj.site) | Q(sites=None), @@ -46,5 +48,6 @@ class ConfigContextQuerySet(QuerySet): Q(platforms=obj.platform) | Q(platforms=None), Q(tenant_groups=tenant_group) | Q(tenant_groups=None), Q(tenants=obj.tenant) | Q(tenants=None), + Q(tags__name__in=tags) | Q(tags=None), is_active=True, ).order_by('weight', 'name') diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index ebefc8c50..8f692e11c 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -370,6 +370,8 @@ class ConfigContextTest(APITestCase): tenantgroup2 = TenantGroup.objects.create(name='Test Tenant Group 2', slug='test-tenant-group-2') tenant1 = Tenant.objects.create(name='Test Tenant 1', slug='test-tenant-1') tenant2 = Tenant.objects.create(name='Test Tenant 2', slug='test-tenant-2') + tag1 = Tag.objects.create(name='Test Tag 1', slug='test-ta-1') + tag2 = Tag.objects.create(name='Test Tag 2', slug='test-ta-2') data = { 'name': 'Test Config Context 4', @@ -380,6 +382,7 @@ class ConfigContextTest(APITestCase): 'platforms': [platform1.pk, platform2.pk], 'tenant_groups': [tenantgroup1.pk, tenantgroup2.pk], 'tenants': [tenant1.pk, tenant2.pk], + 'tags': [tag1.pk, tag2.pk], 'data': {'foo': 'XXX'} } @@ -402,6 +405,8 @@ class ConfigContextTest(APITestCase): self.assertEqual(tenantgroup2.pk, data['tenant_groups'][1]) self.assertEqual(tenant1.pk, data['tenants'][0]) self.assertEqual(tenant2.pk, data['tenants'][1]) + self.assertEqual(tag1.pk, data['tags'][0]) + self.assertEqual(tag2.pk, data['tags'][1]) self.assertEqual(configcontext4.data, data['data']) def test_create_configcontext_bulk(self): diff --git a/netbox/templates/extras/configcontext.html b/netbox/templates/extras/configcontext.html index 3631122c3..353a91580 100644 --- a/netbox/templates/extras/configcontext.html +++ b/netbox/templates/extras/configcontext.html @@ -162,6 +162,20 @@ {% endif %} + + Tags + + {% if configcontext.tags.all %} + + {% else %} + None + {% endif %} + + diff --git a/netbox/templates/extras/configcontext_edit.html b/netbox/templates/extras/configcontext_edit.html index 7a3566a00..d31aa5c57 100644 --- a/netbox/templates/extras/configcontext_edit.html +++ b/netbox/templates/extras/configcontext_edit.html @@ -20,6 +20,7 @@ {% render_field form.platforms %} {% render_field form.tenant_groups %} {% render_field form.tenants %} + {% render_field form.tags %}
diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index 5631a6ec6..10048976b 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -144,7 +144,7 @@ class ObjectListView(View): table.columns.show('pk') # Construct queryset for tags list - if hasattr(model, 'tags'): + if hasattr(model, 'tags') and type(model.tags).__name__ is not 'ManyToManyDescriptor': tags = model.tags.annotate(count=Count('extras_taggeditem_items')).order_by('name') else: tags = None