|
@@ -4,6 +4,7 @@ from django import forms
|
|
|
from django.db.models import Count, Q
|
|
|
|
|
|
from ipam.models import IPAddress
|
|
|
+from tenancy.models import Tenant
|
|
|
from utilities.forms import (
|
|
|
APISelect, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, ExpandableNameField,
|
|
|
FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField,
|
|
@@ -48,7 +49,7 @@ class SiteForm(forms.ModelForm, BootstrapMixin):
|
|
|
|
|
|
class Meta:
|
|
|
model = Site
|
|
|
- fields = ['name', 'slug', 'facility', 'asn', 'physical_address', 'shipping_address', 'comments']
|
|
|
+ fields = ['name', 'slug', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address', 'comments']
|
|
|
widgets = {
|
|
|
'physical_address': SmallTextarea(attrs={'rows': 3}),
|
|
|
'shipping_address': SmallTextarea(attrs={'rows': 3}),
|
|
@@ -63,16 +64,28 @@ class SiteForm(forms.ModelForm, BootstrapMixin):
|
|
|
|
|
|
|
|
|
class SiteFromCSVForm(forms.ModelForm):
|
|
|
+ tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
|
|
|
+ error_messages={'invalid_choice': 'Tenant not found.'})
|
|
|
|
|
|
class Meta:
|
|
|
model = Site
|
|
|
- fields = ['name', 'slug', 'facility', 'asn']
|
|
|
+ fields = ['name', 'slug', 'tenant', 'facility', 'asn']
|
|
|
|
|
|
|
|
|
class SiteImportForm(BulkImportForm, BootstrapMixin):
|
|
|
csv = CSVDataField(csv_form=SiteFromCSVForm)
|
|
|
|
|
|
|
|
|
+def site_tenant_choices():
|
|
|
+ tenant_choices = Tenant.objects.annotate(site_count=Count('sites'))
|
|
|
+ return [(t.slug, u'{} ({})'.format(t.name, t.site_count)) for t in tenant_choices]
|
|
|
+
|
|
|
+
|
|
|
+class SiteFilterForm(forms.Form, BootstrapMixin):
|
|
|
+ tenant = forms.MultipleChoiceField(required=False, choices=site_tenant_choices,
|
|
|
+ widget=forms.SelectMultiple(attrs={'size': 8}))
|
|
|
+
|
|
|
+
|
|
|
#
|
|
|
# Rack groups
|
|
|
#
|
|
@@ -107,7 +120,7 @@ class RackForm(forms.ModelForm, BootstrapMixin):
|
|
|
|
|
|
class Meta:
|
|
|
model = Rack
|
|
|
- fields = ['site', 'group', 'name', 'facility_id', 'u_height', 'comments']
|
|
|
+ fields = ['site', 'group', 'name', 'facility_id', 'tenant', 'u_height', 'comments']
|
|
|
help_texts = {
|
|
|
'site': "The site at which the rack exists",
|
|
|
'name': "Organizational rack name",
|
|
@@ -135,10 +148,12 @@ class RackFromCSVForm(forms.ModelForm):
|
|
|
site = forms.ModelChoiceField(queryset=Site.objects.all(), to_field_name='name',
|
|
|
error_messages={'invalid_choice': 'Site not found.'})
|
|
|
group_name = forms.CharField(required=False)
|
|
|
+ tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
|
|
|
+ error_messages={'invalid_choice': 'Tenant not found.'})
|
|
|
|
|
|
class Meta:
|
|
|
model = Rack
|
|
|
- fields = ['site', 'group_name', 'name', 'facility_id', 'u_height']
|
|
|
+ fields = ['site', 'group_name', 'name', 'facility_id', 'tenant', 'u_height']
|
|
|
|
|
|
def clean(self):
|
|
|
|
|
@@ -161,6 +176,7 @@ class RackBulkEditForm(forms.Form, BootstrapMixin):
|
|
|
pk = forms.ModelMultipleChoiceField(queryset=Rack.objects.all(), widget=forms.MultipleHiddenInput)
|
|
|
site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False)
|
|
|
group = forms.ModelChoiceField(queryset=RackGroup.objects.all(), required=False)
|
|
|
+ tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
|
u_height = forms.IntegerField(required=False, label='Height (U)')
|
|
|
comments = CommentField()
|
|
|
|
|
@@ -175,11 +191,18 @@ def rack_group_choices():
|
|
|
return [(g.pk, u'{} ({})'.format(g, g.rack_count)) for g in group_choices]
|
|
|
|
|
|
|
|
|
+def rack_tenant_choices():
|
|
|
+ tenant_choices = Tenant.objects.annotate(rack_count=Count('racks'))
|
|
|
+ return [(t.slug, u'{} ({})'.format(t.name, t.rack_count)) for t in tenant_choices]
|
|
|
+
|
|
|
+
|
|
|
class RackFilterForm(forms.Form, BootstrapMixin):
|
|
|
site = forms.MultipleChoiceField(required=False, choices=rack_site_choices,
|
|
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
|
|
group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, label='Rack Group',
|
|
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
|
|
+ tenant = forms.MultipleChoiceField(required=False, choices=rack_tenant_choices,
|
|
|
+ widget=forms.SelectMultiple(attrs={'size': 8}))
|
|
|
|
|
|
|
|
|
#
|
|
@@ -203,8 +226,8 @@ class DeviceTypeForm(forms.ModelForm, BootstrapMixin):
|
|
|
|
|
|
class Meta:
|
|
|
model = DeviceType
|
|
|
- fields = ['manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server', 'is_pdu',
|
|
|
- 'is_network_device', 'subdevice_role']
|
|
|
+ fields = ['manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server',
|
|
|
+ 'is_pdu', 'is_network_device', 'subdevice_role']
|
|
|
|
|
|
|
|
|
class DeviceTypeBulkEditForm(forms.Form, BootstrapMixin):
|
|
@@ -324,7 +347,7 @@ class DeviceForm(forms.ModelForm, BootstrapMixin):
|
|
|
|
|
|
class Meta:
|
|
|
model = Device
|
|
|
- fields = ['name', 'device_role', 'device_type', 'serial', 'site', 'rack', 'position', 'face', 'status',
|
|
|
+ fields = ['name', 'device_role', 'tenant', 'device_type', 'serial', 'site', 'rack', 'position', 'face', 'status',
|
|
|
'platform', 'primary_ip4', 'primary_ip6', 'comments']
|
|
|
help_texts = {
|
|
|
'device_role': "The function this device serves",
|
|
@@ -410,6 +433,8 @@ class DeviceForm(forms.ModelForm, BootstrapMixin):
|
|
|
class BaseDeviceFromCSVForm(forms.ModelForm):
|
|
|
device_role = forms.ModelChoiceField(queryset=DeviceRole.objects.all(), to_field_name='name',
|
|
|
error_messages={'invalid_choice': 'Invalid device role.'})
|
|
|
+ tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
|
|
|
+ error_messages={'invalid_choice': 'Tenant not found.'})
|
|
|
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(), to_field_name='name',
|
|
|
error_messages={'invalid_choice': 'Invalid manufacturer.'})
|
|
|
model_name = forms.CharField()
|
|
@@ -441,8 +466,8 @@ class DeviceFromCSVForm(BaseDeviceFromCSVForm):
|
|
|
face = forms.CharField(required=False)
|
|
|
|
|
|
class Meta(BaseDeviceFromCSVForm.Meta):
|
|
|
- fields = ['name', 'device_role', 'manufacturer', 'model_name', 'platform', 'serial', 'site', 'rack_name',
|
|
|
- 'position', 'face']
|
|
|
+ fields = ['name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'site',
|
|
|
+ 'rack_name', 'position', 'face']
|
|
|
|
|
|
def clean(self):
|
|
|
|
|
@@ -477,7 +502,7 @@ class ChildDeviceFromCSVForm(BaseDeviceFromCSVForm):
|
|
|
device_bay_name = forms.CharField(required=False)
|
|
|
|
|
|
class Meta(BaseDeviceFromCSVForm.Meta):
|
|
|
- fields = ['name', 'device_role', 'manufacturer', 'model_name', 'platform', 'serial', 'parent',
|
|
|
+ fields = ['name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'parent',
|
|
|
'device_bay_name']
|
|
|
|
|
|
def clean(self):
|
|
@@ -512,6 +537,7 @@ class DeviceBulkEditForm(forms.Form, BootstrapMixin):
|
|
|
pk = forms.ModelMultipleChoiceField(queryset=Device.objects.all(), widget=forms.MultipleHiddenInput)
|
|
|
device_type = forms.ModelChoiceField(queryset=DeviceType.objects.all(), required=False, label='Type')
|
|
|
device_role = forms.ModelChoiceField(queryset=DeviceRole.objects.all(), required=False, label='Role')
|
|
|
+ tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False, label='Tenant')
|
|
|
platform = forms.ModelChoiceField(queryset=Platform.objects.all(), required=False, label='Platform')
|
|
|
platform_delete = forms.BooleanField(required=False, label='Set platform to "none"')
|
|
|
status = forms.ChoiceField(choices=FORM_STATUS_CHOICES, required=False, initial='', label='Status')
|
|
@@ -533,6 +559,11 @@ def device_role_choices():
|
|
|
return [(r.slug, u'{} ({})'.format(r.name, r.device_count)) for r in role_choices]
|
|
|
|
|
|
|
|
|
+def device_tenant_choices():
|
|
|
+ tenant_choices = Tenant.objects.annotate(device_count=Count('devices'))
|
|
|
+ return [(t.slug, u'{} ({})'.format(t.name, t.device_count)) for t in tenant_choices]
|
|
|
+
|
|
|
+
|
|
|
def device_type_choices():
|
|
|
type_choices = DeviceType.objects.select_related('manufacturer').annotate(device_count=Count('instances'))
|
|
|
return [(t.pk, u'{} ({})'.format(t, t.device_count)) for t in type_choices]
|
|
@@ -550,6 +581,8 @@ class DeviceFilterForm(forms.Form, BootstrapMixin):
|
|
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
|
|
role = forms.MultipleChoiceField(required=False, choices=device_role_choices,
|
|
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
|
|
+ tenant = forms.MultipleChoiceField(required=False, choices=device_tenant_choices,
|
|
|
+ widget=forms.SelectMultiple(attrs={'size': 8}))
|
|
|
device_type_id = forms.MultipleChoiceField(required=False, choices=device_type_choices, label='Type',
|
|
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
|
|
platform = forms.MultipleChoiceField(required=False, choices=device_platform_choices)
|