diff --git a/netbox/circuits/filters.py b/netbox/circuits/filters.py index 12955eeca..f970c828e 100644 --- a/netbox/circuits/filters.py +++ b/netbox/circuits/filters.py @@ -3,7 +3,7 @@ from django.db.models import Q from dcim.models import Site from extras.filters import CustomFieldFilterSet -from tenancy.models import Tenant +from tenancy.models import Tenant, TenantGroup from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter from .constants import CIRCUIT_STATUS_CHOICES from .models import Provider, Circuit, CircuitTermination, CircuitType @@ -87,6 +87,18 @@ class CircuitFilter(CustomFieldFilterSet, django_filters.FilterSet): choices=CIRCUIT_STATUS_CHOICES, null_value=None ) + 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)', diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index 4deee57c9..2a508b3c2 100644 --- a/netbox/circuits/forms.py +++ b/netbox/circuits/forms.py @@ -4,7 +4,7 @@ from taggit.forms import TagField from dcim.models import Site from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm from tenancy.forms import TenancyForm -from tenancy.models import Tenant +from tenancy.models import Tenant, TenantGroup from utilities.forms import ( APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple @@ -292,6 +292,19 @@ class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm): required=False, widget=StaticSelect2Multiple() ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 96ecefafd..4710800c5 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -6,7 +6,7 @@ from netaddr import EUI from netaddr.core import AddrFormatError from extras.filters import CustomFieldFilterSet -from tenancy.models import Tenant +from tenancy.models import Tenant, TenantGroup from utilities.constants import COLOR_CHOICES from utilities.filters import NameSlugSearchFilterSet, NullableCharFieldFilter, NumericInFilter, TagFilter from virtualization.models import Cluster @@ -59,6 +59,18 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet): field_name='slug', label='Region (slug)', ) + 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)', @@ -160,6 +172,18 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet): to_field_name='slug', label='Group', ) + 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)', @@ -241,6 +265,18 @@ class RackReservationFilter(django_filters.FilterSet): to_field_name='slug', label='Group', ) + 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)', @@ -491,6 +527,18 @@ class DeviceFilter(CustomFieldFilterSet): to_field_name='slug', label='Role (slug)', ) + 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)', diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index ad209c516..9c7060bd7 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -13,7 +13,7 @@ from timezone_field import TimeZoneFormField from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm from ipam.models import IPAddress, VLAN, VLANGroup from tenancy.forms import TenancyForm -from tenancy.models import Tenant +from tenancy.models import Tenant, TenantGroup from utilities.forms import ( APISelect, APISelectMultiple, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ChainedFieldsMixin, ChainedModelChoiceField, ColorSelect, CommentField, @@ -276,6 +276,19 @@ class SiteFilterForm(BootstrapMixin, CustomFieldFilterForm): value_field="slug", ) ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', @@ -619,6 +632,19 @@ class RackFilterForm(BootstrapMixin, CustomFieldFilterForm): null_option=True, ) ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', @@ -711,6 +737,19 @@ class RackReservationFilterForm(BootstrapMixin, forms.Form): null_option=True, ) ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', @@ -1703,6 +1742,19 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm): null_option=True, ) ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index f7125ceb0..9e6d4006e 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filters.py @@ -6,7 +6,7 @@ from netaddr.core import AddrFormatError from dcim.models import Site, Device, Interface from extras.filters import CustomFieldFilterSet -from tenancy.models import Tenant +from tenancy.models import Tenant, TenantGroup from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter from virtualization.models import VirtualMachine from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_STATUS_CHOICES, VLAN_STATUS_CHOICES @@ -22,6 +22,18 @@ class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet): method='search', label='Search', ) + 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)', @@ -146,6 +158,18 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet): to_field_name='rd', label='VRF (RD)', ) + 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)', @@ -285,6 +309,18 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet): to_field_name='rd', label='VRF (RD)', ) + 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)', @@ -423,6 +459,18 @@ class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet): to_field_name='slug', label='Group', ) + 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)', diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index d0e25f580..8bc207527 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -6,7 +6,7 @@ from taggit.forms import TagField from dcim.models import Site, Rack, Device, Interface from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm from tenancy.forms import TenancyForm -from tenancy.models import Tenant +from tenancy.models import Tenant, TenantGroup from utilities.forms import ( add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField, CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, ReturnURLForm, SlugField, @@ -103,6 +103,19 @@ class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm): required=False, label='Search' ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', @@ -535,6 +548,19 @@ class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm): null_option=True, ) ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', @@ -984,6 +1010,19 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm): null_option=True, ) ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', @@ -1250,6 +1289,19 @@ class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm): null_option=True, ) ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', diff --git a/netbox/virtualization/filters.py b/netbox/virtualization/filters.py index 0b7e57ba7..32af27adc 100644 --- a/netbox/virtualization/filters.py +++ b/netbox/virtualization/filters.py @@ -6,7 +6,7 @@ from netaddr.core import AddrFormatError from dcim.models import DeviceRole, Interface, Platform, Region, Site from extras.filters import CustomFieldFilterSet -from tenancy.models import Tenant +from tenancy.models import Tenant, TenantGroup from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter from .constants import VM_STATUS_CHOICES from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine @@ -150,6 +150,18 @@ class VirtualMachineFilter(CustomFieldFilterSet): to_field_name='slug', label='Role (slug)', ) + 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)', diff --git a/netbox/virtualization/forms.py b/netbox/virtualization/forms.py index 70bbf0910..931dccc5d 100644 --- a/netbox/virtualization/forms.py +++ b/netbox/virtualization/forms.py @@ -8,7 +8,7 @@ from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, S from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm from ipam.models import IPAddress from tenancy.forms import TenancyForm -from tenancy.models import Tenant +from tenancy.models import Tenant, TenantGroup from utilities.forms import ( add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm, @@ -591,6 +591,19 @@ class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm): required=False, widget=StaticSelect2Multiple() ) + tenant_group = FilterChoiceField( + queryset=TenantGroup.objects.all(), + to_field_name='slug', + null_label='-- None --', + widget=APISelectMultiple( + api_url="/api/tenancy/tenant-groups/", + value_field="slug", + null_option=True, + filter_for={ + 'tenant': 'group' + } + ) + ) tenant = FilterChoiceField( queryset=Tenant.objects.all(), to_field_name='slug',