Просмотр исходного кода

Closes: #4967 - Adds Tenancy to Aggregate model

Daniel Sheppard 5 лет назад
Родитель
Сommit
32274dec86

+ 2 - 1
netbox/ipam/api/serializers.py

@@ -70,11 +70,12 @@ class AggregateSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='ipam-api:aggregate-detail')
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     rir = NestedRIRSerializer()
+    tenant = NestedTenantSerializer(required=False, allow_null=True)
 
     class Meta:
         model = Aggregate
         fields = [
-            'id', 'url', 'family', 'prefix', 'rir', 'date_added', 'description', 'tags', 'custom_fields', 'created',
+            'id', 'url', 'family', 'prefix', 'rir', 'tenant', 'date_added', 'description', 'tags', 'custom_fields', 'created',
             'last_updated',
         ]
         read_only_fields = ['family']

+ 1 - 1
netbox/ipam/filters.py

@@ -122,7 +122,7 @@ class RIRFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
         fields = ['id', 'name', 'slug', 'is_private', 'description']
 
 
-class AggregateFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
+class AggregateFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
     q = django_filters.CharFilter(
         method='search',
         label='Search',

+ 13 - 3
netbox/ipam/forms.py

@@ -225,7 +225,7 @@ class RIRFilterForm(BootstrapMixin, forms.Form):
 # Aggregates
 #
 
-class AggregateForm(BootstrapMixin, CustomFieldModelForm):
+class AggregateForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
     rir = DynamicModelChoiceField(
         queryset=RIR.objects.all()
     )
@@ -237,7 +237,7 @@ class AggregateForm(BootstrapMixin, CustomFieldModelForm):
     class Meta:
         model = Aggregate
         fields = [
-            'prefix', 'rir', 'date_added', 'description', 'tags',
+            'prefix', 'rir', 'date_added', 'description', 'tenant_group', 'tenant', 'tags',
         ]
         help_texts = {
             'prefix': "IPv4 or IPv6 network",
@@ -254,6 +254,12 @@ class AggregateCSVForm(CustomFieldModelCSVForm):
         to_field_name='name',
         help_text='Assigned RIR'
     )
+    tenant = CSVModelChoiceField(
+        queryset=Tenant.objects.all(),
+        required=False,
+        to_field_name='name',
+        help_text='Assigned tenant'
+    )
 
     class Meta:
         model = Aggregate
@@ -270,6 +276,10 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
         required=False,
         label='RIR'
     )
+    tenant = DynamicModelChoiceField(
+        queryset=Tenant.objects.all(),
+        required=False
+    )
     date_added = forms.DateField(
         required=False
     )
@@ -287,7 +297,7 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
         }
 
 
-class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm):
+class AggregateFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Aggregate
     q = forms.CharField(
         required=False,

+ 20 - 0
netbox/ipam/migrations/0043_add_tenancy_to_aggregates.py

@@ -0,0 +1,20 @@
+# Generated by Django 3.1 on 2020-10-16 01:24
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('tenancy', '0011_standardize_name_length'),
+        ('ipam', '0042_standardize_name_length'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='aggregate',
+            name='tenant',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='aggregates', to='tenancy.tenant'),
+        ),
+    ]

+ 10 - 2
netbox/ipam/models.py

@@ -222,6 +222,13 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
         related_name='aggregates',
         verbose_name='RIR'
     )
+    tenant = models.ForeignKey(
+        to='tenancy.Tenant',
+        on_delete=models.PROTECT,
+        related_name='aggregates',
+        blank=True,
+        null=True
+    )
     date_added = models.DateField(
         blank=True,
         null=True
@@ -234,9 +241,9 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
 
     objects = RestrictedQuerySet.as_manager()
 
-    csv_headers = ['prefix', 'rir', 'date_added', 'description']
+    csv_headers = ['prefix', 'rir', 'tenant', 'date_added', 'description']
     clone_fields = [
-        'rir', 'date_added', 'description',
+        'rir', 'tenant', 'date_added', 'description',
     ]
 
     class Meta:
@@ -289,6 +296,7 @@ class Aggregate(ChangeLoggedModel, CustomFieldModel):
         return (
             self.prefix,
             self.rir.name,
+            self.tenant.name if self.tenant else None,
             self.date_added,
             self.description,
         )

+ 6 - 3
netbox/ipam/tables.py

@@ -253,6 +253,9 @@ class AggregateTable(BaseTable):
     prefix = tables.LinkColumn(
         verbose_name='Aggregate'
     )
+    tenant = tables.TemplateColumn(
+        template_code=TENANT_LINK
+    )
     date_added = tables.DateColumn(
         format="Y-m-d",
         verbose_name='Added'
@@ -260,7 +263,7 @@ class AggregateTable(BaseTable):
 
     class Meta(BaseTable.Meta):
         model = Aggregate
-        fields = ('pk', 'prefix', 'rir', 'date_added', 'description')
+        fields = ('pk', 'prefix', 'rir', 'tenant', 'date_added', 'description')
 
 
 class AggregateDetailTable(AggregateTable):
@@ -276,8 +279,8 @@ class AggregateDetailTable(AggregateTable):
     )
 
     class Meta(AggregateTable.Meta):
-        fields = ('pk', 'prefix', 'rir', 'child_count', 'utilization', 'date_added', 'description', 'tags')
-        default_columns = ('pk', 'prefix', 'rir', 'child_count', 'utilization', 'date_added', 'description')
+        fields = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description', 'tags')
+        default_columns = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description')
 
 
 #

+ 39 - 6
netbox/ipam/tests/test_filters.py

@@ -240,13 +240,28 @@ class AggregateTestCase(TestCase):
         )
         RIR.objects.bulk_create(rirs)
 
+        tenant_groups = (
+            TenantGroup(name='Tenant group 1', slug='tenant-group-1'),
+            TenantGroup(name='Tenant group 2', slug='tenant-group-2'),
+            TenantGroup(name='Tenant group 3', slug='tenant-group-3'),
+        )
+        for tenantgroup in tenant_groups:
+            tenantgroup.save()
+
+        tenants = (
+            Tenant(name='Tenant 1', slug='tenant-1', group=tenant_groups[0]),
+            Tenant(name='Tenant 2', slug='tenant-2', group=tenant_groups[1]),
+            Tenant(name='Tenant 3', slug='tenant-3', group=tenant_groups[2]),
+        )
+        Tenant.objects.bulk_create(tenants)
+
         aggregates = (
-            Aggregate(prefix='10.1.0.0/16', rir=rirs[0], date_added='2020-01-01'),
-            Aggregate(prefix='10.2.0.0/16', rir=rirs[0], date_added='2020-01-02'),
-            Aggregate(prefix='10.3.0.0/16', rir=rirs[1], date_added='2020-01-03'),
-            Aggregate(prefix='2001:db8:1::/48', rir=rirs[1], date_added='2020-01-04'),
-            Aggregate(prefix='2001:db8:2::/48', rir=rirs[2], date_added='2020-01-05'),
-            Aggregate(prefix='2001:db8:3::/48', rir=rirs[2], date_added='2020-01-06'),
+            Aggregate(prefix='10.1.0.0/16', rir=rirs[0], tenant=tenants[0], date_added='2020-01-01'),
+            Aggregate(prefix='10.2.0.0/16', rir=rirs[0], tenant=tenants[1], date_added='2020-01-02'),
+            Aggregate(prefix='10.3.0.0/16', rir=rirs[1], tenant=tenants[2], date_added='2020-01-03'),
+            Aggregate(prefix='2001:db8:1::/48', rir=rirs[1], tenant=tenants[0], date_added='2020-01-04'),
+            Aggregate(prefix='2001:db8:2::/48', rir=rirs[2], tenant=tenants[1], date_added='2020-01-05'),
+            Aggregate(prefix='2001:db8:3::/48', rir=rirs[2], tenant=tenants[2], date_added='2020-01-06'),
         )
         Aggregate.objects.bulk_create(aggregates)
 
@@ -274,6 +289,24 @@ class AggregateTestCase(TestCase):
         params = {'rir': [rirs[0].slug, rirs[1].slug]}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
 
+    def test_tenant(self):
+        tenants = Tenant.objects.all()[:2]
+        params = {'tenant_id': [tenants[0].pk, tenants[1].pk]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
+        print(self.filterset(params, self.queryset).qs.count())
+        params = {'tenant': [tenants[0].slug, tenants[1].slug]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
+        print(self.filterset(params, self.queryset).qs.count())
+
+    def test_tenant_group(self):
+        tenant_groups = TenantGroup.objects.all()[:2]
+        params = {'tenant_group_id': [tenant_groups[0].pk, tenant_groups[1].pk]}
+        print(self.filterset(params, self.queryset).qs.count())
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
+        params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
+        print(self.filterset(params, self.queryset).qs.count())
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
+
 
 class RoleTestCase(TestCase):
     queryset = Role.objects.all()

+ 7 - 0
netbox/templates/ipam/aggregate_edit.html

@@ -11,6 +11,13 @@
             {% render_field form.description %}
         </div>
     </div>
+    <div class="panel panel-default">
+        <div class="panel-heading"><strong>Tenancy</strong></div>
+        <div class="panel-body">
+            {% render_field form.tenant_group %}
+            {% render_field form.tenant %}
+        </div>
+    </div>
     {% if form.custom_fields %}
         <div class="panel panel-default">
             <div class="panel-heading"><strong>Custom Fields</strong></div>