mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
functional dynamic filter lookups
This commit is contained in:
@ -29,12 +29,14 @@ class ProviderFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilte
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='circuits__terminations__site__region__in',
|
field_name='circuits__terminations__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='circuits__terminations__site__region__in',
|
field_name='circuits__terminations__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -120,12 +122,14 @@ class CircuitFilterSet(BaseFilterSet, CustomFieldFilterSet, TenancyFilterSet, Cr
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='terminations__site__region__in',
|
field_name='terminations__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='terminations__site__region__in',
|
field_name='terminations__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
|
@ -7,7 +7,7 @@ from tenancy.models import Tenant
|
|||||||
from utilities.constants import COLOR_CHOICES
|
from utilities.constants import COLOR_CHOICES
|
||||||
from utilities.filters import (
|
from utilities.filters import (
|
||||||
BaseFilterSet, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter,
|
BaseFilterSet, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter,
|
||||||
BaseFilterSet, NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter,
|
NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter,
|
||||||
)
|
)
|
||||||
from virtualization.models import Cluster
|
from virtualization.models import Cluster
|
||||||
from .choices import *
|
from .choices import *
|
||||||
@ -92,12 +92,14 @@ class SiteFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='region__in',
|
field_name='region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='region__in',
|
field_name='region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -134,12 +136,14 @@ class SiteFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
|
|||||||
class RackGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
class RackGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -177,12 +181,14 @@ class RackFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -402,7 +408,7 @@ class DeviceTypeFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFil
|
|||||||
return queryset.exclude(device_bay_templates__isnull=value)
|
return queryset.exclude(device_bay_templates__isnull=value)
|
||||||
|
|
||||||
|
|
||||||
class DeviceTypeComponentFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet):
|
||||||
devicetype_id = django_filters.ModelMultipleChoiceFilter(
|
devicetype_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
queryset=DeviceType.objects.all(),
|
queryset=DeviceType.objects.all(),
|
||||||
field_name='device_type_id',
|
field_name='device_type_id',
|
||||||
@ -410,56 +416,56 @@ class DeviceTypeComponentFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConsolePortTemplateFilterSet(DeviceTypeComponentFilterSet):
|
class ConsolePortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsolePortTemplate
|
model = ConsolePortTemplate
|
||||||
fields = ['id', 'name', 'type']
|
fields = ['id', 'name', 'type']
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPortTemplateFilterSet(DeviceTypeComponentFilterSet):
|
class ConsoleServerPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsoleServerPortTemplate
|
model = ConsoleServerPortTemplate
|
||||||
fields = ['id', 'name', 'type']
|
fields = ['id', 'name', 'type']
|
||||||
|
|
||||||
|
|
||||||
class PowerPortTemplateFilterSet(DeviceTypeComponentFilterSet):
|
class PowerPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPortTemplate
|
model = PowerPortTemplate
|
||||||
fields = ['id', 'name', 'type', 'maximum_draw', 'allocated_draw']
|
fields = ['id', 'name', 'type', 'maximum_draw', 'allocated_draw']
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletTemplateFilterSet(DeviceTypeComponentFilterSet):
|
class PowerOutletTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutletTemplate
|
model = PowerOutletTemplate
|
||||||
fields = ['id', 'name', 'type', 'feed_leg']
|
fields = ['id', 'name', 'type', 'feed_leg']
|
||||||
|
|
||||||
|
|
||||||
class InterfaceTemplateFilterSet(DeviceTypeComponentFilterSet):
|
class InterfaceTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InterfaceTemplate
|
model = InterfaceTemplate
|
||||||
fields = ['id', 'name', 'type', 'mgmt_only']
|
fields = ['id', 'name', 'type', 'mgmt_only']
|
||||||
|
|
||||||
|
|
||||||
class FrontPortTemplateFilterSet(DeviceTypeComponentFilterSet):
|
class FrontPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FrontPortTemplate
|
model = FrontPortTemplate
|
||||||
fields = ['id', 'name', 'type']
|
fields = ['id', 'name', 'type']
|
||||||
|
|
||||||
|
|
||||||
class RearPortTemplateFilterSet(DeviceTypeComponentFilterSet):
|
class RearPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RearPortTemplate
|
model = RearPortTemplate
|
||||||
fields = ['id', 'name', 'type', 'positions']
|
fields = ['id', 'name', 'type', 'positions']
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayTemplateFilterSet(DeviceTypeComponentFilterSet):
|
class DeviceBayTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceBayTemplate
|
model = DeviceBayTemplate
|
||||||
@ -538,12 +544,14 @@ class DeviceFilterSet(BaseFilterSet, LocalConfigContextFilterSet, CustomFieldFil
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -690,19 +698,21 @@ class DeviceFilterSet(BaseFilterSet, LocalConfigContextFilterSet, CustomFieldFil
|
|||||||
return queryset.exclude(device_bays__isnull=value)
|
return queryset.exclude(device_bays__isnull=value)
|
||||||
|
|
||||||
|
|
||||||
class DeviceComponentFilterSet(BaseFilterSet):
|
class DeviceComponentFilterSet(django_filters.FilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='device__site__region__in',
|
field_name='device__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='device__site__region__in',
|
field_name='device__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -738,7 +748,7 @@ class DeviceComponentFilterSet(BaseFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConsolePortFilterSet(DeviceComponentFilterSet):
|
class ConsolePortFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
type = django_filters.MultipleChoiceFilter(
|
type = django_filters.MultipleChoiceFilter(
|
||||||
choices=ConsolePortTypeChoices,
|
choices=ConsolePortTypeChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
@ -754,7 +764,7 @@ class ConsolePortFilterSet(DeviceComponentFilterSet):
|
|||||||
fields = ['id', 'name', 'description', 'connection_status']
|
fields = ['id', 'name', 'description', 'connection_status']
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPortFilterSet(DeviceComponentFilterSet):
|
class ConsoleServerPortFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
type = django_filters.MultipleChoiceFilter(
|
type = django_filters.MultipleChoiceFilter(
|
||||||
choices=ConsolePortTypeChoices,
|
choices=ConsolePortTypeChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
@ -770,7 +780,7 @@ class ConsoleServerPortFilterSet(DeviceComponentFilterSet):
|
|||||||
fields = ['id', 'name', 'description', 'connection_status']
|
fields = ['id', 'name', 'description', 'connection_status']
|
||||||
|
|
||||||
|
|
||||||
class PowerPortFilterSet(DeviceComponentFilterSet):
|
class PowerPortFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
type = django_filters.MultipleChoiceFilter(
|
type = django_filters.MultipleChoiceFilter(
|
||||||
choices=PowerPortTypeChoices,
|
choices=PowerPortTypeChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
@ -786,7 +796,7 @@ class PowerPortFilterSet(DeviceComponentFilterSet):
|
|||||||
fields = ['id', 'name', 'maximum_draw', 'allocated_draw', 'description', 'connection_status']
|
fields = ['id', 'name', 'maximum_draw', 'allocated_draw', 'description', 'connection_status']
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletFilterSet(DeviceComponentFilterSet):
|
class PowerOutletFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
type = django_filters.MultipleChoiceFilter(
|
type = django_filters.MultipleChoiceFilter(
|
||||||
choices=PowerOutletTypeChoices,
|
choices=PowerOutletTypeChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
@ -802,7 +812,7 @@ class PowerOutletFilterSet(DeviceComponentFilterSet):
|
|||||||
fields = ['id', 'name', 'feed_leg', 'description', 'connection_status']
|
fields = ['id', 'name', 'feed_leg', 'description', 'connection_status']
|
||||||
|
|
||||||
|
|
||||||
class InterfaceFilterSet(DeviceComponentFilterSet):
|
class InterfaceFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
@ -900,7 +910,7 @@ class InterfaceFilterSet(DeviceComponentFilterSet):
|
|||||||
}.get(value, queryset.none())
|
}.get(value, queryset.none())
|
||||||
|
|
||||||
|
|
||||||
class FrontPortFilterSet(DeviceComponentFilterSet):
|
class FrontPortFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
cabled = django_filters.BooleanFilter(
|
cabled = django_filters.BooleanFilter(
|
||||||
field_name='cable',
|
field_name='cable',
|
||||||
lookup_expr='isnull',
|
lookup_expr='isnull',
|
||||||
@ -912,7 +922,7 @@ class FrontPortFilterSet(DeviceComponentFilterSet):
|
|||||||
fields = ['id', 'name', 'type', 'description']
|
fields = ['id', 'name', 'type', 'description']
|
||||||
|
|
||||||
|
|
||||||
class RearPortFilterSet(DeviceComponentFilterSet):
|
class RearPortFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
cabled = django_filters.BooleanFilter(
|
cabled = django_filters.BooleanFilter(
|
||||||
field_name='cable',
|
field_name='cable',
|
||||||
lookup_expr='isnull',
|
lookup_expr='isnull',
|
||||||
@ -924,26 +934,28 @@ class RearPortFilterSet(DeviceComponentFilterSet):
|
|||||||
fields = ['id', 'name', 'type', 'positions', 'description']
|
fields = ['id', 'name', 'type', 'positions', 'description']
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayFilterSet(DeviceComponentFilterSet):
|
class DeviceBayFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceBay
|
model = DeviceBay
|
||||||
fields = ['id', 'name', 'description']
|
fields = ['id', 'name', 'description']
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemFilterSet(DeviceComponentFilterSet):
|
class InventoryItemFilterSet(BaseFilterSet, DeviceComponentFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='device__site__region__in',
|
field_name='device__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='device__site__region__in',
|
field_name='device__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -1009,12 +1021,14 @@ class VirtualChassisFilterSet(BaseFilterSet):
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='master__site__region__in',
|
field_name='master__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='master__site__region__in',
|
field_name='master__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -1226,12 +1240,14 @@ class PowerPanelFilterSet(BaseFilterSet):
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -1275,12 +1291,14 @@ class PowerFeedFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='power_panel__site__region__in',
|
field_name='power_panel__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='power_panel__site__region__in',
|
field_name='power_panel__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
|
@ -235,7 +235,7 @@ class ConfigContextFilterSet(BaseFilterSet):
|
|||||||
# Filter for Local Config Context Data
|
# Filter for Local Config Context Data
|
||||||
#
|
#
|
||||||
|
|
||||||
class LocalConfigContextFilterSet(BaseFilterSet):
|
class LocalConfigContextFilterSet(django_filters.FilterSet):
|
||||||
local_context_data = django_filters.BooleanFilter(
|
local_context_data = django_filters.BooleanFilter(
|
||||||
method='_local_context_data',
|
method='_local_context_data',
|
||||||
label='Has local config context data',
|
label='Has local config context data',
|
||||||
|
@ -28,8 +28,8 @@ class GraphTestCase(TestCase):
|
|||||||
Graph.objects.bulk_create(graphs)
|
Graph.objects.bulk_create(graphs)
|
||||||
|
|
||||||
def test_name(self):
|
def test_name(self):
|
||||||
params = {'name': 'Graph 1'}
|
params = {'name': ['Graph 1', 'Graph 2']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_type(self):
|
def test_type(self):
|
||||||
content_type = ContentType.objects.filter(GRAPH_MODELS).first()
|
content_type = ContentType.objects.filter(GRAPH_MODELS).first()
|
||||||
@ -59,8 +59,8 @@ class ExportTemplateTestCase(TestCase):
|
|||||||
ExportTemplate.objects.bulk_create(export_templates)
|
ExportTemplate.objects.bulk_create(export_templates)
|
||||||
|
|
||||||
def test_name(self):
|
def test_name(self):
|
||||||
params = {'name': 'Export Template 1'}
|
params = {'name': ['Export Template 1', 'Export Template 2']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_content_type(self):
|
def test_content_type(self):
|
||||||
params = {'content_type': ContentType.objects.get(model='site').pk}
|
params = {'content_type': ContentType.objects.get(model='site').pk}
|
||||||
@ -154,8 +154,8 @@ class ConfigContextTestCase(TestCase):
|
|||||||
c.tenants.set([tenants[i]])
|
c.tenants.set([tenants[i]])
|
||||||
|
|
||||||
def test_name(self):
|
def test_name(self):
|
||||||
params = {'name': 'Config Context 1'}
|
params = {'name': ['Config Context 1', 'Config Context 2']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_is_active(self):
|
def test_is_active(self):
|
||||||
params = {'is_active': True}
|
params = {'is_active': True}
|
||||||
|
@ -8,7 +8,8 @@ from dcim.models import Device, Interface, Region, Site
|
|||||||
from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet
|
from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet
|
||||||
from tenancy.filters import TenancyFilterSet
|
from tenancy.filters import TenancyFilterSet
|
||||||
from utilities.filters import (
|
from utilities.filters import (
|
||||||
MultiValueCharFilter, NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter,
|
BaseFilterSet, MultiValueCharFilter, NameSlugSearchFilterSet, NumericInFilter, TagFilter,
|
||||||
|
TreeNodeMultipleChoiceFilter,
|
||||||
)
|
)
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
from .choices import *
|
from .choices import *
|
||||||
@ -28,7 +29,7 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class VRFFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
class VRFFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -53,7 +54,7 @@ class VRFFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterS
|
|||||||
fields = ['name', 'rd', 'enforce_unique']
|
fields = ['name', 'rd', 'enforce_unique']
|
||||||
|
|
||||||
|
|
||||||
class RIRFilterSet(NameSlugSearchFilterSet):
|
class RIRFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -64,7 +65,7 @@ class RIRFilterSet(NameSlugSearchFilterSet):
|
|||||||
fields = ['name', 'slug', 'is_private']
|
fields = ['name', 'slug', 'is_private']
|
||||||
|
|
||||||
|
|
||||||
class AggregateFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
class AggregateFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -114,7 +115,7 @@ class AggregateFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
|||||||
return queryset.none()
|
return queryset.none()
|
||||||
|
|
||||||
|
|
||||||
class RoleFilterSet(NameSlugSearchFilterSet):
|
class RoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
@ -125,7 +126,7 @@ class RoleFilterSet(NameSlugSearchFilterSet):
|
|||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class PrefixFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
class PrefixFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -166,12 +167,14 @@ class PrefixFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -273,7 +276,7 @@ class PrefixFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
|
|||||||
return queryset.filter(prefix__net_mask_length=value)
|
return queryset.filter(prefix__net_mask_length=value)
|
||||||
|
|
||||||
|
|
||||||
class IPAddressFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -395,15 +398,17 @@ class IPAddressFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedF
|
|||||||
return queryset.exclude(interface__isnull=value)
|
return queryset.exclude(interface__isnull=value)
|
||||||
|
|
||||||
|
|
||||||
class VLANGroupFilterSet(NameSlugSearchFilterSet):
|
class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -423,7 +428,7 @@ class VLANGroupFilterSet(NameSlugSearchFilterSet):
|
|||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class VLANFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
class VLANFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -434,12 +439,14 @@ class VLANFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilter
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -494,7 +501,7 @@ class VLANFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilter
|
|||||||
return queryset.filter(qs_filter)
|
return queryset.filter(qs_filter)
|
||||||
|
|
||||||
|
|
||||||
class ServiceFilterSet(CreatedUpdatedFilterSet):
|
class ServiceFilterSet(BaseFilterSet, CreatedUpdatedFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
|
@ -3,7 +3,7 @@ from django.db.models import Q
|
|||||||
|
|
||||||
from dcim.models import Device
|
from dcim.models import Device
|
||||||
from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet
|
from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet
|
||||||
from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
|
from utilities.filters import BaseFilterSet, NameSlugSearchFilterSet, NumericInFilter, TagFilter
|
||||||
from .models import Secret, SecretRole
|
from .models import Secret, SecretRole
|
||||||
|
|
||||||
|
|
||||||
@ -13,14 +13,14 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SecretRoleFilterSet(NameSlugSearchFilterSet):
|
class SecretRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SecretRole
|
model = SecretRole
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class SecretFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
class SecretFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
|
@ -13,14 +13,14 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TenantGroupFilterSet(NameSlugSearchFilterSet):
|
class TenantGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TenantGroup
|
model = TenantGroup
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class TenantFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
class TenantFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import django_filters
|
import django_filters
|
||||||
|
from copy import deepcopy
|
||||||
from dcim.forms import MACAddressField
|
from dcim.forms import MACAddressField
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django_filters.utils import get_model_field
|
from django_filters.utils import get_model_field, resolve_field
|
||||||
|
|
||||||
from extras.models import Tag
|
from extras.models import Tag
|
||||||
from utilities.constants import (
|
from utilities.constants import (
|
||||||
@ -120,13 +121,62 @@ class BaseFilterSet(django_filters.FilterSet):
|
|||||||
"""
|
"""
|
||||||
A base filterset which provides common functionaly to all NetBox filtersets
|
A base filterset which provides common functionaly to all NetBox filtersets
|
||||||
"""
|
"""
|
||||||
|
FILTER_DEFAULTS = deepcopy(django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS)
|
||||||
|
FILTER_DEFAULTS.update({
|
||||||
|
models.AutoField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.CharField: {
|
||||||
|
'filter_class': MultiValueCharFilter
|
||||||
|
},
|
||||||
|
models.DateField: {
|
||||||
|
'filter_class': MultiValueDateFilter
|
||||||
|
},
|
||||||
|
models.DateTimeField: {
|
||||||
|
'filter_class': MultiValueDateTimeFilter
|
||||||
|
},
|
||||||
|
models.DecimalField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.EmailField: {
|
||||||
|
'filter_class': MultiValueCharFilter
|
||||||
|
},
|
||||||
|
models.FloatField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.IntegerField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.PositiveIntegerField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.PositiveSmallIntegerField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.SlugField: {
|
||||||
|
'filter_class': MultiValueCharFilter
|
||||||
|
},
|
||||||
|
models.SmallIntegerField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.TimeField: {
|
||||||
|
'filter_class': MultiValueTimeFilter
|
||||||
|
},
|
||||||
|
models.URLField: {
|
||||||
|
'filter_class': MultiValueCharFilter
|
||||||
|
},
|
||||||
|
MACAddressField: {
|
||||||
|
'filter_class': MultiValueMACAddressFilter
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_filters(cls):
|
def get_filters(cls):
|
||||||
"""
|
"""
|
||||||
Override filter generation to support dynamic lookup expressions for certain filter types.
|
Override filter generation to support dynamic lookup expressions for certain filter types.
|
||||||
|
|
||||||
For specific filter types, new filters are created based on defined lookup expressions in
|
For specific filter types, new filters are created based on defined lookup expressions in
|
||||||
the form `<field_name>_<lookup_expr>`
|
the form `<field_name>__<lookup_expr>`
|
||||||
"""
|
"""
|
||||||
filters = super().get_filters()
|
filters = super().get_filters()
|
||||||
|
|
||||||
@ -136,7 +186,7 @@ class BaseFilterSet(django_filters.FilterSet):
|
|||||||
|
|
||||||
# It the filter makes use of a custom filter method or lookup expression skip it
|
# It the filter makes use of a custom filter method or lookup expression skip it
|
||||||
# as we cannot sanely handle these cases in a generic mannor
|
# as we cannot sanely handle these cases in a generic mannor
|
||||||
if existing_filter.method is not None or existing_filter.lookup_expr != 'exact':
|
if existing_filter.method is not None or existing_filter.lookup_expr not in ['exact', 'in']:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Choose the lookup expression map based on the filter type
|
# Choose the lookup expression map based on the filter type
|
||||||
@ -169,7 +219,7 @@ class BaseFilterSet(django_filters.FilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Do no augment any other filter types with more lookup expressions
|
# Do not augment any other filter types with more lookup expressions
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Get properties of the existing filter for later use
|
# Get properties of the existing filter for later use
|
||||||
@ -178,24 +228,29 @@ class BaseFilterSet(django_filters.FilterSet):
|
|||||||
|
|
||||||
# Create new filters for each lookup expression in the map
|
# Create new filters for each lookup expression in the map
|
||||||
for lookup_name, lookup_expr in lookup_map.items():
|
for lookup_name, lookup_expr in lookup_map.items():
|
||||||
new_filter_name = '{}_{}'.format(existing_filter_name, lookup_name)
|
new_filter_name = '{}__{}'.format(existing_filter_name, lookup_name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print(existing_filter_name)
|
if existing_filter_name in cls.declared_filters:
|
||||||
new_filter = cls.filter_for_field(field, field_name, lookup_expr)
|
resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid
|
||||||
|
new_filter = type(existing_filter)(
|
||||||
|
field_name=field_name,
|
||||||
|
lookup_expr=lookup_expr,
|
||||||
|
label=existing_filter.label,
|
||||||
|
exclude=existing_filter.exclude,
|
||||||
|
distinct=existing_filter.distinct,
|
||||||
|
**existing_filter.extra
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
new_filter = cls.filter_for_field(field, field_name, lookup_expr)
|
||||||
except django_filters.exceptions.FieldLookupError:
|
except django_filters.exceptions.FieldLookupError:
|
||||||
# The filter could not be created because the lookup expression is not supported
|
# The filter could not be created because the lookup expression is not supported on the field
|
||||||
continue
|
continue
|
||||||
|
|
||||||
help_text = FILTER_LOOKUP_HELP_TEXT_MAP[lookup_expr]
|
|
||||||
|
|
||||||
if lookup_name.startswith('n'):
|
if lookup_name.startswith('n'):
|
||||||
# This is a negation filter which requires a queryselt.exclud() clause
|
# This is a negation filter which requires a queryselt.exclud() clause
|
||||||
new_filter.exclude = True
|
new_filter.exclude = True
|
||||||
help_text = 'negated {}'.format(help_text)
|
|
||||||
|
|
||||||
new_filter.extra = existing_filter.extra
|
|
||||||
new_filter.extra['help_text'] = '{} - {}'.format(field_name, help_text)
|
|
||||||
new_filters[new_filter_name] = new_filter
|
new_filters[new_filter_name] = new_filter
|
||||||
|
|
||||||
filters.update(new_filters)
|
filters.update(new_filters)
|
||||||
@ -218,54 +273,3 @@ class NameSlugSearchFilterSet(django_filters.FilterSet):
|
|||||||
models.Q(name__icontains=value) |
|
models.Q(name__icontains=value) |
|
||||||
models.Q(slug__icontains=value)
|
models.Q(slug__icontains=value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Update default filters
|
|
||||||
#
|
|
||||||
|
|
||||||
FILTER_DEFAULTS = django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS
|
|
||||||
FILTER_DEFAULTS.update({
|
|
||||||
models.AutoField: {
|
|
||||||
'filter_class': MultiValueNumberFilter
|
|
||||||
},
|
|
||||||
models.CharField: {
|
|
||||||
'filter_class': MultiValueCharFilter
|
|
||||||
},
|
|
||||||
models.DateField: {
|
|
||||||
'filter_class': MultiValueDateFilter
|
|
||||||
},
|
|
||||||
models.DateTimeField: {
|
|
||||||
'filter_class': MultiValueDateTimeFilter
|
|
||||||
},
|
|
||||||
models.DecimalField: {
|
|
||||||
'filter_class': MultiValueNumberFilter
|
|
||||||
},
|
|
||||||
models.EmailField: {
|
|
||||||
'filter_class': MultiValueCharFilter
|
|
||||||
},
|
|
||||||
models.FloatField: {
|
|
||||||
'filter_class': MultiValueNumberFilter
|
|
||||||
},
|
|
||||||
models.IntegerField: {
|
|
||||||
'filter_class': MultiValueNumberFilter
|
|
||||||
},
|
|
||||||
models.PositiveIntegerField: {
|
|
||||||
'filter_class': MultiValueNumberFilter
|
|
||||||
},
|
|
||||||
models.PositiveSmallIntegerField: {
|
|
||||||
'filter_class': MultiValueNumberFilter
|
|
||||||
},
|
|
||||||
models.SlugField: {
|
|
||||||
'filter_class': MultiValueCharFilter
|
|
||||||
},
|
|
||||||
models.SmallIntegerField: {
|
|
||||||
'filter_class': MultiValueNumberFilter
|
|
||||||
},
|
|
||||||
models.TimeField: {
|
|
||||||
'filter_class': MultiValueTimeFilter
|
|
||||||
},
|
|
||||||
models.URLField: {
|
|
||||||
'filter_class': MultiValueCharFilter
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
@ -6,7 +6,8 @@ from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet, LocalC
|
|||||||
from tenancy.filters import TenancyFilterSet
|
from tenancy.filters import TenancyFilterSet
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.filters import (
|
from utilities.filters import (
|
||||||
MultiValueMACAddressFilter, NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter,
|
BaseFilterSet, MultiValueMACAddressFilter, NameSlugSearchFilterSet, NumericInFilter, TagFilter,
|
||||||
|
TreeNodeMultipleChoiceFilter,
|
||||||
)
|
)
|
||||||
from .choices import *
|
from .choices import *
|
||||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||||
@ -20,21 +21,21 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ClusterTypeFilterSet(NameSlugSearchFilterSet):
|
class ClusterTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClusterType
|
model = ClusterType
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class ClusterGroupFilterSet(NameSlugSearchFilterSet):
|
class ClusterGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClusterGroup
|
model = ClusterGroup
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class ClusterFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
class ClusterFilterSet(BaseFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -45,12 +46,14 @@ class ClusterFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='site__region__in',
|
field_name='site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -104,6 +107,7 @@ class ClusterFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
|
|||||||
|
|
||||||
|
|
||||||
class VirtualMachineFilterSet(
|
class VirtualMachineFilterSet(
|
||||||
|
BaseFilterSet,
|
||||||
LocalConfigContextFilterSet,
|
LocalConfigContextFilterSet,
|
||||||
TenancyFilterSet,
|
TenancyFilterSet,
|
||||||
CustomFieldFilterSet,
|
CustomFieldFilterSet,
|
||||||
@ -149,12 +153,14 @@ class VirtualMachineFilterSet(
|
|||||||
)
|
)
|
||||||
region_id = TreeNodeMultipleChoiceFilter(
|
region_id = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='cluster__site__region__in',
|
field_name='cluster__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
label='Region (ID)',
|
label='Region (ID)',
|
||||||
)
|
)
|
||||||
region = TreeNodeMultipleChoiceFilter(
|
region = TreeNodeMultipleChoiceFilter(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
field_name='cluster__site__region__in',
|
field_name='cluster__site__region',
|
||||||
|
lookup_expr='in',
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Region (slug)',
|
label='Region (slug)',
|
||||||
)
|
)
|
||||||
@ -208,7 +214,7 @@ class VirtualMachineFilterSet(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class InterfaceFilterSet(django_filters.FilterSet):
|
class InterfaceFilterSet(BaseFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
|
Reference in New Issue
Block a user