1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Merge branch 'develop' into 2921-tags-select2

This commit is contained in:
Saria Hajjar
2020-01-16 15:33:42 +00:00
1030 changed files with 94332 additions and 6656 deletions

View File

@@ -31,11 +31,12 @@ class TenantSerializer(TaggitSerializer, CustomFieldModelSerializer):
virtualmachine_count = serializers.IntegerField(read_only=True)
vlan_count = serializers.IntegerField(read_only=True)
vrf_count = serializers.IntegerField(read_only=True)
cluster_count = serializers.IntegerField(read_only=True)
class Meta:
model = Tenant
fields = [
'id', 'name', 'slug', 'group', 'description', 'comments', 'tags', 'custom_fields', 'created',
'last_updated', 'circuit_count', 'device_count', 'ipaddress_count', 'prefix_count', 'rack_count',
'site_count', 'virtualmachine_count', 'vlan_count', 'vrf_count',
'site_count', 'virtualmachine_count', 'vlan_count', 'vrf_count', 'cluster_count',
]

View File

@@ -27,7 +27,7 @@ class TenantGroupViewSet(ModelViewSet):
tenant_count=get_subquery(Tenant, 'group')
)
serializer_class = serializers.TenantGroupSerializer
filterset_class = filters.TenantGroupFilter
filterset_class = filters.TenantGroupFilterSet
#
@@ -49,4 +49,4 @@ class TenantViewSet(CustomFieldModelViewSet):
vrf_count=get_subquery(VRF, 'tenant')
)
serializer_class = serializers.TenantSerializer
filterset_class = filters.TenantFilter
filterset_class = filters.TenantFilterSet

View File

@@ -7,19 +7,20 @@ from .models import Tenant, TenantGroup
__all__ = (
'TenantFilter',
'TenantGroupFilter',
'TenancyFilterSet',
'TenantFilterSet',
'TenantGroupFilterSet',
)
class TenantGroupFilter(NameSlugSearchFilterSet):
class TenantGroupFilterSet(NameSlugSearchFilterSet):
class Meta:
model = TenantGroup
fields = ['id', 'name', 'slug']
class TenantFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
class TenantFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
id__in = NumericInFilter(
field_name='id',
lookup_expr='in'
@@ -53,3 +54,31 @@ class TenantFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
Q(description__icontains=value) |
Q(comments__icontains=value)
)
class TenancyFilterSet(django_filters.FilterSet):
"""
An inheritable FilterSet for models which support Tenant assignment.
"""
tenant_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='tenant__group__id',
queryset=TenantGroup.objects.all(),
to_field_name='id',
label='Tenant Group (ID)',
)
tenant_group = django_filters.ModelMultipleChoiceFilter(
field_name='tenant__group__slug',
queryset=TenantGroup.objects.all(),
to_field_name='slug',
label='Tenant Group (slug)',
)
tenant_id = django_filters.ModelMultipleChoiceFilter(
queryset=Tenant.objects.all(),
label='Tenant (ID)',
)
tenant = django_filters.ModelMultipleChoiceFilter(
field_name='tenant__slug',
queryset=Tenant.objects.all(),
to_field_name='slug',
label='Tenant (slug)',
)

View File

@@ -1,28 +0,0 @@
import django_filters
from .models import Tenant, TenantGroup
class TenancyFilterSet(django_filters.FilterSet):
tenant_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='tenant__group__id',
queryset=TenantGroup.objects.all(),
to_field_name='id',
label='Tenant Group (ID)',
)
tenant_group = django_filters.ModelMultipleChoiceFilter(
field_name='tenant__group__slug',
queryset=TenantGroup.objects.all(),
to_field_name='slug',
label='Tenant Group (slug)',
)
tenant_id = django_filters.ModelMultipleChoiceFilter(
queryset=Tenant.objects.all(),
label='Tenant (ID)',
)
tenant = django_filters.ModelMultipleChoiceFilter(
field_name='tenant__slug',
queryset=Tenant.objects.all(),
to_field_name='slug',
label='Tenant (slug)',
)

View File

@@ -0,0 +1,45 @@
import django.db.models.deletion
import taggit.managers
from django.db import migrations, models
class Migration(migrations.Migration):
replaces = [('tenancy', '0001_initial'), ('tenancy', '0002_tenant_group_optional'), ('tenancy', '0003_unicode_literals'), ('tenancy', '0004_tags'), ('tenancy', '0005_change_logging')]
dependencies = [
('taggit', '0002_auto_20150616_2121'),
]
operations = [
migrations.CreateModel(
name='TenantGroup',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, unique=True)),
('slug', models.SlugField(unique=True)),
('created', models.DateField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
],
options={
'ordering': ['name'],
},
),
migrations.CreateModel(
name='Tenant',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
('name', models.CharField(max_length=30, unique=True)),
('slug', models.SlugField(unique=True)),
('description', models.CharField(blank=True, help_text='Long-form name (optional)', max_length=100)),
('comments', models.TextField(blank=True)),
('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tenants', to='tenancy.TenantGroup')),
('tags', taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
],
options={
'ordering': ['group', 'name'],
},
),
]

View File

@@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.14 on 2018-07-31 02:12
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
replaces = [('tenancy', '0002_tenant_group_optional'), ('tenancy', '0003_unicode_literals')]
dependencies = [
('tenancy', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='tenant',
name='group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tenants', to='tenancy.TenantGroup'),
),
migrations.AlterField(
model_name='tenant',
name='description',
field=models.CharField(blank=True, help_text='Long-form name (optional)', max_length=100),
),
]

View File

@@ -7,6 +7,12 @@ from extras.models import CustomFieldModel, TaggedItem
from utilities.models import ChangeLoggedModel
__all__ = (
'Tenant',
'TenantGroup',
)
class TenantGroup(ChangeLoggedModel):
"""
An arbitrary collection of Tenants.
@@ -73,6 +79,9 @@ class Tenant(ChangeLoggedModel, CustomFieldModel):
tags = TaggableManager(through=TaggedItem)
csv_headers = ['name', 'slug', 'group', 'description', 'comments']
clone_fields = [
'group', 'description',
]
class Meta:
ordering = ['group', 'name']

View File

@@ -5,6 +5,23 @@ from tenancy.models import Tenant, TenantGroup
from utilities.testing import APITestCase
class AppTest(APITestCase):
def test_root(self):
url = reverse('tenancy-api:api-root')
response = self.client.get('{}?format=api'.format(url), **self.header)
self.assertEqual(response.status_code, 200)
def test_choices(self):
url = reverse('tenancy-api:field-choice-list')
response = self.client.get(url, **self.header)
self.assertEqual(response.status_code, 200)
class TenantGroupTest(APITestCase):
def setUp(self):

View File

@@ -6,7 +6,7 @@ from tenancy.models import Tenant, TenantGroup
class TenantGroupTestCase(TestCase):
queryset = TenantGroup.objects.all()
filterset = TenantGroupFilter
filterset = TenantGroupFilterSet
@classmethod
def setUpTestData(cls):
@@ -34,7 +34,7 @@ class TenantGroupTestCase(TestCase):
class TenantTestCase(TestCase):
queryset = Tenant.objects.all()
filterset = TenantFilter
filterset = TenantFilterSet
@classmethod
def setUpTestData(cls):

View File

@@ -10,7 +10,12 @@ from utilities.testing import create_test_user
class TenantGroupTestCase(TestCase):
def setUp(self):
user = create_test_user(permissions=['tenancy.view_tenantgroup'])
user = create_test_user(
permissions=[
'tenancy.view_tenantgroup',
'tenancy.add_tenantgroup',
]
)
self.client = Client()
self.client.force_login(user)
@@ -27,11 +32,30 @@ class TenantGroupTestCase(TestCase):
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200)
def test_tenantgroup_import(self):
csv_data = (
"name,slug",
"Tenant Group 4,tenant-group-4",
"Tenant Group 5,tenant-group-5",
"Tenant Group 6,tenant-group-6",
)
response = self.client.post(reverse('tenancy:tenantgroup_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200)
self.assertEqual(TenantGroup.objects.count(), 6)
class TenantTestCase(TestCase):
def setUp(self):
user = create_test_user(permissions=['tenancy.view_tenant'])
user = create_test_user(
permissions=[
'tenancy.view_tenant',
'tenancy.add_tenant',
]
)
self.client = Client()
self.client.force_login(user)
@@ -59,3 +83,17 @@ class TenantTestCase(TestCase):
tenant = Tenant.objects.first()
response = self.client.get(tenant.get_absolute_url(), follow=True)
self.assertEqual(response.status_code, 200)
def test_tenant_import(self):
csv_data = (
"name,slug",
"Tenant 4,tenant-4",
"Tenant 5,tenant-5",
"Tenant 6,tenant-6",
)
response = self.client.post(reverse('tenancy:tenant_import'), {'csv': '\n'.join(csv_data)})
self.assertEqual(response.status_code, 200)
self.assertEqual(Tenant.objects.count(), 6)

View File

@@ -9,7 +9,7 @@ from ipam.models import IPAddress, Prefix, VLAN, VRF
from utilities.views import (
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
)
from virtualization.models import VirtualMachine
from virtualization.models import VirtualMachine, Cluster
from . import filters, forms, tables
from .models import Tenant, TenantGroup
@@ -57,8 +57,8 @@ class TenantGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class TenantListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'tenancy.view_tenant'
queryset = Tenant.objects.prefetch_related('group')
filter = filters.TenantFilter
filter_form = forms.TenantFilterForm
filterset = filters.TenantFilterSet
filterset_form = forms.TenantFilterForm
table = tables.TenantTable
template_name = 'tenancy/tenant_list.html'
@@ -80,6 +80,7 @@ class TenantView(PermissionRequiredMixin, View):
'vlan_count': VLAN.objects.filter(tenant=tenant).count(),
'circuit_count': Circuit.objects.filter(tenant=tenant).count(),
'virtualmachine_count': VirtualMachine.objects.filter(tenant=tenant).count(),
'cluster_count': Cluster.objects.filter(tenant=tenant).count(),
}
return render(request, 'tenancy/tenant.html', {
@@ -116,7 +117,7 @@ class TenantBulkImportView(PermissionRequiredMixin, BulkImportView):
class TenantBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'tenancy.change_tenant'
queryset = Tenant.objects.prefetch_related('group')
filter = filters.TenantFilter
filterset = filters.TenantFilterSet
table = tables.TenantTable
form = forms.TenantBulkEditForm
default_return_url = 'tenancy:tenant_list'
@@ -125,6 +126,6 @@ class TenantBulkEditView(PermissionRequiredMixin, BulkEditView):
class TenantBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'tenancy.delete_tenant'
queryset = Tenant.objects.prefetch_related('group')
filter = filters.TenantFilter
filterset = filters.TenantFilterSet
table = tables.TenantTable
default_return_url = 'tenancy:tenant_list'