Преглед изворни кода

Closes #2388: Enable filtering of devices/VMs by region

Jeremy Stretch пре 7 година
родитељ
комит
b4998f4b01
5 измењених фајлова са 56 додато и 3 уклоњено
  1. 1 0
      CHANGELOG.md
  2. 21 0
      netbox/dcim/filters.py
  3. 5 0
      netbox/dcim/forms.py
  4. 22 1
      netbox/virtualization/filters.py
  5. 7 2
      netbox/virtualization/forms.py

+ 1 - 0
CHANGELOG.md

@@ -2,6 +2,7 @@ v2.4.7 (FUTURE)
 
 ## 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
 * [#2512](https://github.com/digitalocean/netbox/issues/2512) - Add device field to inventory item filter form
 

+ 21 - 0
netbox/dcim/filters.py

@@ -2,6 +2,7 @@ from __future__ import unicode_literals
 
 import django_filters
 from django.contrib.auth.models import User
+from django.core.exceptions import ObjectDoesNotExist
 from django.db.models import Q
 from netaddr import EUI
 from netaddr.core import AddrFormatError
@@ -456,6 +457,16 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
     )
     name = 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(
         queryset=Site.objects.all(),
         label='Site (ID)',
@@ -538,6 +549,16 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
             Q(comments__icontains=value)
         ).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):
         value = value.strip()
         if not value:

+ 5 - 0
netbox/dcim/forms.py

@@ -1108,6 +1108,11 @@ class DeviceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
 class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Device
     q = forms.CharField(required=False, label='Search')
+    region = FilterTreeNodeMultipleChoiceField(
+        queryset=Region.objects.all(),
+        to_field_name='slug',
+        required=False,
+    )
     site = FilterChoiceField(
         queryset=Site.objects.annotate(filter_count=Count('devices')),
         to_field_name='slug',

+ 22 - 1
netbox/virtualization/filters.py

@@ -1,11 +1,12 @@
 from __future__ import unicode_literals
 
 import django_filters
+from django.core.exceptions import ObjectDoesNotExist
 from django.db.models import Q
 from netaddr import EUI
 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 tenancy.models import Tenant
 from utilities.filters import NumericInFilter
@@ -116,6 +117,16 @@ class VirtualMachineFilter(CustomFieldFilterSet):
         queryset=Cluster.objects.all(),
         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(
         name='cluster__site',
         queryset=Site.objects.all(),
@@ -173,6 +184,16 @@ class VirtualMachineFilter(CustomFieldFilterSet):
             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):
     virtual_machine_id = django_filters.ModelMultipleChoiceFilter(

+ 7 - 2
netbox/virtualization/forms.py

@@ -16,8 +16,8 @@ from tenancy.models import Tenant
 from utilities.forms import (
     AnnotatedMultipleChoiceField, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
     ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm,
-    ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, JSONField, SlugField, SmallTextarea,
-    add_blank_choice
+    ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, FilterTreeNodeMultipleChoiceField,
+    JSONField, SlugField, SmallTextarea, add_blank_choice,
 )
 from .constants import VM_STATUS_CHOICES
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
@@ -386,6 +386,11 @@ class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
         queryset=Cluster.objects.annotate(filter_count=Count('virtual_machines')),
         label='Cluster'
     )
+    region = FilterTreeNodeMultipleChoiceField(
+        queryset=Region.objects.all(),
+        to_field_name='slug',
+        required=False,
+    )
     site = FilterChoiceField(
         queryset=Site.objects.annotate(filter_count=Count('clusters__virtual_machines')),
         to_field_name='slug',