mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 03:56:53 -06:00
parent
b38bb64c81
commit
57f199f899
@ -3,6 +3,7 @@
|
||||
## Bug Fixes
|
||||
|
||||
* [#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
|
||||
|
||||
---
|
||||
|
||||
|
@ -18,6 +18,17 @@ class ProviderFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||
method='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(
|
||||
field_name='circuits__terminations__site',
|
||||
queryset=Site.objects.all(),
|
||||
|
@ -104,6 +104,18 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
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',
|
||||
|
@ -93,6 +93,17 @@ class SiteFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
|
||||
|
||||
|
||||
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(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site (ID)',
|
||||
@ -125,6 +136,17 @@ class RackFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
|
||||
method='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)',
|
||||
@ -831,6 +853,28 @@ class InventoryItemFilter(DeviceComponentFilterSet):
|
||||
method='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(
|
||||
queryset=Device.objects.all(),
|
||||
label='Device (ID)',
|
||||
@ -880,6 +924,17 @@ class VirtualChassisFilter(django_filters.FilterSet):
|
||||
method='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(
|
||||
field_name='master__site',
|
||||
queryset=Site.objects.all(),
|
||||
@ -1078,6 +1133,17 @@ class PowerPanelFilter(django_filters.FilterSet):
|
||||
method='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)',
|
||||
@ -1116,6 +1182,17 @@ class PowerFeedFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||
method='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(
|
||||
field_name='power_panel__site',
|
||||
queryset=Site.objects.all(),
|
||||
|
@ -364,6 +364,18 @@ class RackGroupCSVForm(forms.ModelForm):
|
||||
|
||||
|
||||
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(
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
@ -635,11 +647,23 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
||||
|
||||
class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
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(
|
||||
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',
|
||||
@ -3386,6 +3410,29 @@ class InventoryItemFilterForm(BootstrapMixin, forms.Form):
|
||||
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',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
filter_for={
|
||||
'device_id': 'site'
|
||||
}
|
||||
)
|
||||
)
|
||||
device_id = FilterChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
required=False,
|
||||
@ -3551,6 +3598,18 @@ class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
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',
|
||||
@ -3656,6 +3715,18 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
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',
|
||||
@ -3876,6 +3947,18 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
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',
|
||||
|
@ -4,10 +4,10 @@ from django.core.exceptions import ValidationError
|
||||
from django.db.models import Q
|
||||
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 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 .constants import *
|
||||
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',
|
||||
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(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site (ID)',
|
||||
@ -375,6 +386,17 @@ class IPAddressFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
|
||||
|
||||
|
||||
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(
|
||||
queryset=Site.objects.all(),
|
||||
label='Site (ID)',
|
||||
@ -400,6 +422,17 @@ class VLANFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
|
||||
method='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)',
|
||||
|
@ -3,7 +3,7 @@ from django.core.exceptions import MultipleObjectsReturned
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
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 tenancy.forms import TenancyFilterForm, TenancyForm
|
||||
from tenancy.models import Tenant
|
||||
@ -492,8 +492,8 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
||||
class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
model = Prefix
|
||||
field_order = [
|
||||
'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'status', 'site', 'role', 'tenant_group', 'tenant',
|
||||
'is_pool', 'expand',
|
||||
'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'status', 'region', 'site', 'role', 'tenant_group',
|
||||
'tenant', 'is_pool', 'expand',
|
||||
]
|
||||
q = forms.CharField(
|
||||
required=False,
|
||||
@ -534,6 +534,18 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
|
||||
required=False,
|
||||
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(
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
@ -1034,6 +1046,18 @@ class VLANGroupCSVForm(forms.ModelForm):
|
||||
|
||||
|
||||
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(
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
@ -1215,11 +1239,24 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
||||
|
||||
class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
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(
|
||||
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',
|
||||
'group_id': 'region'
|
||||
}
|
||||
)
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
|
@ -36,6 +36,27 @@ class ClusterFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||
method='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(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
label='Parent group (ID)',
|
||||
@ -56,16 +77,6 @@ class ClusterFilter(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||
to_field_name='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()
|
||||
|
||||
class Meta:
|
||||
|
@ -173,6 +173,29 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
|
||||
class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
model = Cluster
|
||||
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(
|
||||
queryset=ClusterType.objects.all(),
|
||||
to_field_name='slug',
|
||||
@ -193,17 +216,6 @@ class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
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):
|
||||
|
Loading…
Reference in New Issue
Block a user