mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Closes #2388: Enable filtering of devices/VMs by region
This commit is contained in:
parent
51295389c6
commit
b4998f4b01
@ -2,6 +2,7 @@ v2.4.7 (FUTURE)
|
|||||||
|
|
||||||
## Enhancements
|
## Enhancements
|
||||||
|
|
||||||
|
* [#2388](https://github.com/digitalocean/netbox/issues/2388) - Enable filtering of devices/VMs by region
|
||||||
* [#2427](https://github.com/digitalocean/netbox/issues/2427) - Allow filtering of interfaces by assigned VLAN or VLAN ID
|
* [#2427](https://github.com/digitalocean/netbox/issues/2427) - Allow filtering of interfaces by assigned VLAN or VLAN ID
|
||||||
* [#2512](https://github.com/digitalocean/netbox/issues/2512) - Add device field to inventory item filter form
|
* [#2512](https://github.com/digitalocean/netbox/issues/2512) - Add device field to inventory item filter form
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import django_filters
|
import django_filters
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from netaddr import EUI
|
from netaddr import EUI
|
||||||
from netaddr.core import AddrFormatError
|
from netaddr.core import AddrFormatError
|
||||||
@ -456,6 +457,16 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
)
|
)
|
||||||
name = NullableCharFieldFilter()
|
name = NullableCharFieldFilter()
|
||||||
asset_tag = NullableCharFieldFilter()
|
asset_tag = NullableCharFieldFilter()
|
||||||
|
region_id = django_filters.NumberFilter(
|
||||||
|
method='filter_region',
|
||||||
|
name='pk',
|
||||||
|
label='Region (ID)',
|
||||||
|
)
|
||||||
|
region = django_filters.CharFilter(
|
||||||
|
method='filter_region',
|
||||||
|
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)',
|
||||||
@ -538,6 +549,16 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
Q(comments__icontains=value)
|
Q(comments__icontains=value)
|
||||||
).distinct()
|
).distinct()
|
||||||
|
|
||||||
|
def filter_region(self, queryset, name, value):
|
||||||
|
try:
|
||||||
|
region = Region.objects.get(**{name: value})
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
return queryset.none()
|
||||||
|
return queryset.filter(
|
||||||
|
Q(site__region=region) |
|
||||||
|
Q(site__region__in=region.get_descendants())
|
||||||
|
)
|
||||||
|
|
||||||
def _mac_address(self, queryset, name, value):
|
def _mac_address(self, queryset, name, value):
|
||||||
value = value.strip()
|
value = value.strip()
|
||||||
if not value:
|
if not value:
|
||||||
|
@ -1108,6 +1108,11 @@ class DeviceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|||||||
class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
model = Device
|
model = Device
|
||||||
q = forms.CharField(required=False, label='Search')
|
q = forms.CharField(required=False, label='Search')
|
||||||
|
region = FilterTreeNodeMultipleChoiceField(
|
||||||
|
queryset=Region.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
site = FilterChoiceField(
|
site = FilterChoiceField(
|
||||||
queryset=Site.objects.annotate(filter_count=Count('devices')),
|
queryset=Site.objects.annotate(filter_count=Count('devices')),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import django_filters
|
import django_filters
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from netaddr import EUI
|
from netaddr import EUI
|
||||||
from netaddr.core import AddrFormatError
|
from netaddr.core import AddrFormatError
|
||||||
|
|
||||||
from dcim.models import DeviceRole, Interface, Platform, Site
|
from dcim.models import DeviceRole, Interface, Platform, Region, Site
|
||||||
from extras.filters import CustomFieldFilterSet
|
from extras.filters import CustomFieldFilterSet
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.filters import NumericInFilter
|
from utilities.filters import NumericInFilter
|
||||||
@ -116,6 +117,16 @@ class VirtualMachineFilter(CustomFieldFilterSet):
|
|||||||
queryset=Cluster.objects.all(),
|
queryset=Cluster.objects.all(),
|
||||||
label='Cluster (ID)',
|
label='Cluster (ID)',
|
||||||
)
|
)
|
||||||
|
region_id = django_filters.NumberFilter(
|
||||||
|
method='filter_region',
|
||||||
|
name='pk',
|
||||||
|
label='Region (ID)',
|
||||||
|
)
|
||||||
|
region = django_filters.CharFilter(
|
||||||
|
method='filter_region',
|
||||||
|
name='slug',
|
||||||
|
label='Region (slug)',
|
||||||
|
)
|
||||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
name='cluster__site',
|
name='cluster__site',
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
@ -173,6 +184,16 @@ class VirtualMachineFilter(CustomFieldFilterSet):
|
|||||||
Q(comments__icontains=value)
|
Q(comments__icontains=value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def filter_region(self, queryset, name, value):
|
||||||
|
try:
|
||||||
|
region = Region.objects.get(**{name: value})
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
return queryset.none()
|
||||||
|
return queryset.filter(
|
||||||
|
Q(cluster__site__region=region) |
|
||||||
|
Q(cluster__site__region__in=region.get_descendants())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class InterfaceFilter(django_filters.FilterSet):
|
class InterfaceFilter(django_filters.FilterSet):
|
||||||
virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
|
virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
@ -16,8 +16,8 @@ from tenancy.models import Tenant
|
|||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
AnnotatedMultipleChoiceField, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
|
AnnotatedMultipleChoiceField, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
|
||||||
ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm,
|
ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm,
|
||||||
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, JSONField, SlugField, SmallTextarea,
|
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, FilterTreeNodeMultipleChoiceField,
|
||||||
add_blank_choice
|
JSONField, SlugField, SmallTextarea, add_blank_choice,
|
||||||
)
|
)
|
||||||
from .constants import VM_STATUS_CHOICES
|
from .constants import VM_STATUS_CHOICES
|
||||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||||
@ -386,6 +386,11 @@ class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
queryset=Cluster.objects.annotate(filter_count=Count('virtual_machines')),
|
queryset=Cluster.objects.annotate(filter_count=Count('virtual_machines')),
|
||||||
label='Cluster'
|
label='Cluster'
|
||||||
)
|
)
|
||||||
|
region = FilterTreeNodeMultipleChoiceField(
|
||||||
|
queryset=Region.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
site = FilterChoiceField(
|
site = FilterChoiceField(
|
||||||
queryset=Site.objects.annotate(filter_count=Count('clusters__virtual_machines')),
|
queryset=Site.objects.annotate(filter_count=Count('clusters__virtual_machines')),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
|
Loading…
Reference in New Issue
Block a user