Fixes #3833: Add region and region_id filters where missing (#3836)

This commit is contained in:
Jeremy Stretch 2020-01-03 13:52:50 -05:00 committed by GitHub
parent b38bb64c81
commit 57f199f899
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 305 additions and 28 deletions

View File

@ -3,6 +3,7 @@
## Bug Fixes ## Bug Fixes
* [#3831](https://github.com/netbox-community/netbox/issues/3831) - Fix API-driven filter field rendering (#3812 regression) * [#3831](https://github.com/netbox-community/netbox/issues/3831) - Fix API-driven filter field rendering (#3812 regression)
* [#3833](https://github.com/netbox-community/netbox/issues/3833) - Add missing region filters for multiple objects
--- ---

View File

@ -18,6 +18,17 @@ class ProviderFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
method='search', method='search',
label='Search', label='Search',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='circuits__terminations__site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='circuits__terminations__site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
field_name='circuits__terminations__site', field_name='circuits__terminations__site',
queryset=Site.objects.all(), queryset=Site.objects.all(),

View File

@ -104,6 +104,18 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
required=False, required=False,
label='Search' label='Search'
) )
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',

View File

@ -93,6 +93,17 @@ class SiteFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
class RackGroupFilter(NameSlugSearchFilterSet): class RackGroupFilter(NameSlugSearchFilterSet):
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label='Site (ID)',
@ -125,6 +136,17 @@ class RackFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
method='search', method='search',
label='Search', label='Search',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label='Site (ID)',
@ -831,6 +853,28 @@ class InventoryItemFilter(DeviceComponentFilterSet):
method='search', method='search',
label='Search', label='Search',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='device__site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='device__site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter(
field_name='device__site',
queryset=Site.objects.all(),
label='Site (ID)',
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='device__site__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label='Site name (slug)',
)
device_id = django_filters.ModelChoiceFilter( device_id = django_filters.ModelChoiceFilter(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label='Device (ID)', label='Device (ID)',
@ -880,6 +924,17 @@ class VirtualChassisFilter(django_filters.FilterSet):
method='search', method='search',
label='Search', label='Search',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='master__site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='master__site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
field_name='master__site', field_name='master__site',
queryset=Site.objects.all(), queryset=Site.objects.all(),
@ -1078,6 +1133,17 @@ class PowerPanelFilter(django_filters.FilterSet):
method='search', method='search',
label='Search', label='Search',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label='Site (ID)',
@ -1116,6 +1182,17 @@ class PowerFeedFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
method='search', method='search',
label='Search', label='Search',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='power_panel__site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='power_panel__site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
field_name='power_panel__site', field_name='power_panel__site',
queryset=Site.objects.all(), queryset=Site.objects.all(),

View File

@ -364,6 +364,18 @@ class RackGroupCSVForm(forms.ModelForm):
class RackGroupFilterForm(BootstrapMixin, forms.Form): class RackGroupFilterForm(BootstrapMixin, forms.Form):
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
@ -635,11 +647,23 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
model = Rack model = Rack
field_order = ['q', 'site', 'group_id', 'status', 'role', 'tenant_group', 'tenant'] field_order = ['q', 'region', 'site', 'group_id', 'status', 'role', 'tenant_group', 'tenant']
q = forms.CharField( q = forms.CharField(
required=False, required=False,
label='Search' label='Search'
) )
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
@ -3386,6 +3410,29 @@ class InventoryItemFilterForm(BootstrapMixin, forms.Form):
required=False, required=False,
label='Search' label='Search'
) )
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField(
queryset=Site.objects.all(),
to_field_name='slug',
widget=APISelectMultiple(
api_url="/api/dcim/sites/",
value_field="slug",
filter_for={
'device_id': 'site'
}
)
)
device_id = FilterChoiceField( device_id = FilterChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
required=False, required=False,
@ -3551,6 +3598,18 @@ class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm):
required=False, required=False,
label='Search' label='Search'
) )
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
@ -3656,6 +3715,18 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldFilterForm):
required=False, required=False,
label='Search' label='Search'
) )
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
@ -3876,6 +3947,18 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldFilterForm):
required=False, required=False,
label='Search' label='Search'
) )
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',

View File

@ -4,10 +4,10 @@ from django.core.exceptions import ValidationError
from django.db.models import Q from django.db.models import Q
from netaddr.core import AddrFormatError from netaddr.core import AddrFormatError
from dcim.models import Site, Device, Interface from dcim.models import Device, Interface, Region, Site
from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet
from tenancy.filtersets import TenancyFilterSet from tenancy.filtersets import TenancyFilterSet
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
from virtualization.models import VirtualMachine from virtualization.models import VirtualMachine
from .constants import * from .constants import *
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
@ -149,6 +149,17 @@ class PrefixFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterS
to_field_name='rd', to_field_name='rd',
label='VRF (RD)', label='VRF (RD)',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label='Site (ID)',
@ -375,6 +386,17 @@ class IPAddressFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
class VLANGroupFilter(NameSlugSearchFilterSet): class VLANGroupFilter(NameSlugSearchFilterSet):
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label='Site (ID)',
@ -400,6 +422,17 @@ class VLANFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
method='search', method='search',
label='Search', label='Search',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label='Site (ID)',

View File

@ -3,7 +3,7 @@ from django.core.exceptions import MultipleObjectsReturned
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from taggit.forms import TagField from taggit.forms import TagField
from dcim.models import Site, Rack, Device, Interface from dcim.models import Device, Interface, Rack, Region, Site
from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
from tenancy.forms import TenancyFilterForm, TenancyForm from tenancy.forms import TenancyFilterForm, TenancyForm
from tenancy.models import Tenant from tenancy.models import Tenant
@ -492,8 +492,8 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
model = Prefix model = Prefix
field_order = [ field_order = [
'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'status', 'site', 'role', 'tenant_group', 'tenant', 'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'status', 'region', 'site', 'role', 'tenant_group',
'is_pool', 'expand', 'tenant', 'is_pool', 'expand',
] ]
q = forms.CharField( q = forms.CharField(
required=False, required=False,
@ -534,6 +534,18 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
required=False, required=False,
widget=StaticSelect2Multiple() widget=StaticSelect2Multiple()
) )
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
@ -1034,6 +1046,18 @@ class VLANGroupCSVForm(forms.ModelForm):
class VLANGroupFilterForm(BootstrapMixin, forms.Form): class VLANGroupFilterForm(BootstrapMixin, forms.Form):
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region',
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
@ -1215,11 +1239,24 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
model = VLAN model = VLAN
field_order = ['q', 'site', 'group_id', 'status', 'role', 'tenant_group', 'tenant'] field_order = ['q', 'region', 'site', 'group_id', 'status', 'role', 'tenant_group', 'tenant']
q = forms.CharField( q = forms.CharField(
required=False, required=False,
label='Search' label='Search'
) )
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region',
'group_id': 'region'
}
)
)
site = FilterChoiceField( site = FilterChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',

View File

@ -36,6 +36,27 @@ class ClusterFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
method='search', method='search',
label='Search', label='Search',
) )
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
label='Region (ID)',
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region__in',
to_field_name='slug',
label='Region (slug)',
)
site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(),
label='Site (ID)',
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='site__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label='Site (slug)',
)
group_id = django_filters.ModelMultipleChoiceFilter( group_id = django_filters.ModelMultipleChoiceFilter(
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
label='Parent group (ID)', label='Parent group (ID)',
@ -56,16 +77,6 @@ class ClusterFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
to_field_name='slug', to_field_name='slug',
label='Cluster type (slug)', label='Cluster type (slug)',
) )
site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(),
label='Site (ID)',
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='site__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label='Site (slug)',
)
tag = TagFilter() tag = TagFilter()
class Meta: class Meta:

View File

@ -173,6 +173,29 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm): class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Cluster model = Cluster
q = forms.CharField(required=False, label='Search') q = forms.CharField(required=False, label='Search')
region = FilterChoiceField(
queryset=Region.objects.all(),
to_field_name='slug',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/regions/",
value_field="slug",
filter_for={
'site': 'region'
}
)
)
site = FilterChoiceField(
queryset=Site.objects.all(),
to_field_name='slug',
null_label='-- None --',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/sites/",
value_field='slug',
null_option=True,
)
)
type = FilterChoiceField( type = FilterChoiceField(
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
to_field_name='slug', to_field_name='slug',
@ -193,17 +216,6 @@ class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
null_option=True, null_option=True,
) )
) )
site = FilterChoiceField(
queryset=Site.objects.all(),
to_field_name='slug',
null_label='-- None --',
required=False,
widget=APISelectMultiple(
api_url="/api/dcim/sites/",
value_field='slug',
null_option=True,
)
)
class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form): class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):