add filters / housekeeping (#384)

This commit is contained in:
Mario
2023-09-25 17:28:32 +02:00
committed by GitHub
parent 86c0c55896
commit dbe331afb8
2 changed files with 362 additions and 162 deletions
+114 -10
View File
@@ -1,38 +1,59 @@
import django_filters
from dcim.choices import DeviceStatusChoices
from dcim.models import Device, DeviceRole, Location, Rack, Region, Site, SiteGroup
from dcim.models import Device, DeviceRole, Location, Rack, Region, Site, SiteGroup, Manufacturer, DeviceType, Platform
from django.db.models import Q
from extras.filtersets import LocalConfigContextFilterSet
from extras.models import ConfigTemplate
from netbox.filtersets import NetBoxModelFilterSet
from tenancy.filtersets import TenancyFilterSet
from utilities.filters import TreeNodeMultipleChoiceFilter
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
from utilities.filters import TreeNodeMultipleChoiceFilter, MultiValueCharFilter, MultiValueMACAddressFilter
from netbox_topology_views.models import CoordinateGroup, Coordinate
class DeviceFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
class DeviceFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet, LocalConfigContextFilterSet):
q = django_filters.CharFilter(
method="search",
label="Search",
)
manufacturer_id = django_filters.ModelMultipleChoiceFilter(
field_name='device_type__manufacturer',
queryset=Manufacturer.objects.all(),
label="Manufacturer (ID)",
)
manufacturer = django_filters.ModelMultipleChoiceFilter(
field_name='device_type__manufacturer__slug',
queryset=Manufacturer.objects.all(),
to_field_name='slug',
label="Manufacturer (slug)",
)
device_type_id = django_filters.ModelMultipleChoiceFilter(
queryset=DeviceType.objects.all(),
label="Device type (ID)",
)
role_id = django_filters.ModelMultipleChoiceFilter(
field_name="role_id",
queryset=DeviceRole.objects.all(),
label="Role (ID)",
)
platform_id = django_filters.ModelMultipleChoiceFilter(
queryset=Platform.objects.all(),
label="Platform (ID)",
)
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name="site__region",
lookup_expr="in",
label="Region (ID)",
)
site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(),
label="Site (ID)",
)
sitegroup_id = TreeNodeMultipleChoiceFilter(
site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
field_name="site__group",
lookup_expr="in",
label="Site Group (ID)",
)
site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(),
label="Site (ID)",
)
location_id = TreeNodeMultipleChoiceFilter(
queryset=Location.objects.all(),
field_name="location",
@@ -48,10 +69,57 @@ class DeviceFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
choices=DeviceStatusChoices,
null_value=None,
)
mac_address = MultiValueMACAddressFilter(
field_name='interfaces__mac_address',
label="MAC address",
)
serial = MultiValueCharFilter(
lookup_expr='iexact'
)
console_ports = django_filters.BooleanFilter(
method='_console_ports',
label="Has console ports",
)
console_server_ports = django_filters.BooleanFilter(
method='_console_server_ports',
label="Has console server ports",
)
power_ports = django_filters.BooleanFilter(
method='_power_ports',
label="Has power ports",
)
power_outlets = django_filters.BooleanFilter(
method='_power_outlets',
label="Has power outlets",
)
interfaces = django_filters.BooleanFilter(
method='_interfaces',
label="Has interfaces",
)
pass_through_ports = django_filters.BooleanFilter(
method='_pass_through_ports',
label="Has pass-through ports",
)
config_template_id = django_filters.ModelMultipleChoiceFilter(
queryset=ConfigTemplate.objects.all(),
label="Config template (ID)",
)
has_primary_ip = django_filters.BooleanFilter(
method='_has_primary_ip',
label="Has a primary IP",
)
has_oob_ip = django_filters.BooleanFilter(
method='_has_oob_ip',
label="Has an out-of-band IP",
)
virtual_chassis_member = django_filters.BooleanFilter(
method='_virtual_chassis_member',
label="Is a virtual chassis member",
)
class Meta:
model = Device
fields = ["id", "name"]
fields = ["id", "name", "asset_tag", "airflow"]
def search(self, queryset, name, value):
"""Perform the filtered search."""
@@ -60,6 +128,42 @@ class DeviceFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
qs_filter = Q(name__icontains=value)
return queryset.filter(qs_filter)
def _console_ports(self, queryset, name, value):
return queryset.exclude(consoleports__isnull=value)
def _console_server_ports(self, queryset, name, value):
return queryset.exclude(consoleserverports__isnull=value)
def _power_ports(self, queryset, name, value):
return queryset.exclude(powerports__isnull=value)
def _power_outlets(self, queryset, name, value):
return queryset.exclude(poweroutlets__isnull=value)
def _interfaces(self, queryset, name, value):
return queryset.exclude(interfaces__isnull=value)
def _pass_through_ports(self, queryset, name, value):
return queryset.exclude(
frontports__isnull=value,
rearports__isnull=value
)
def _has_primary_ip(self, queryset, name, value):
params = Q(primary_ip4__isnull=False) | Q(primary_ip6__isnull=False)
if value:
return queryset.filter(params)
return queryset.exclude(params)
def _has_oob_ip(self, queryset, name, value):
params = Q(oob_ip__isnull=False)
if value:
return queryset.filter(params)
return queryset.exclude(params)
def _virtual_chassis_member(self, queryset, name, value):
return queryset.exclude(virtual_chassis__isnull=value)
class CoordinatesFilterSet(NetBoxModelFilterSet):
group = django_filters.ModelMultipleChoiceFilter(
queryset = CoordinateGroup.objects.all(),
+248 -152
View File
@@ -5,14 +5,17 @@ from django.conf import settings
from django.utils.translation import gettext as _
from dcim.models import Device, Site, SiteGroup, Region, DeviceRole, Location, Rack
from dcim.models import Device, Site, SiteGroup, Region, DeviceRole, Location, Rack, Manufacturer, DeviceType, Platform
from django import forms
from dcim.choices import DeviceStatusChoices
from dcim.choices import DeviceStatusChoices, DeviceAirflowChoices
from tenancy.models import TenantGroup, Tenant
from tenancy.forms import TenancyFilterForm
from extras.models import ConfigTemplate
from extras.forms import LocalConfigContextFilterForm
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
from django.conf import settings
from netbox.forms import NetBoxModelFilterSetForm, NetBoxModelForm, NetBoxModelImportForm
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, add_blank_choice
from utilities.forms.fields import (
TagFilterField,
DynamicModelMultipleChoiceField
@@ -20,146 +23,239 @@ from utilities.forms.fields import (
from netbox_topology_views.models import IndividualOptions, CoordinateGroup, Coordinate
class DeviceFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
class DeviceFilterForm(
LocalConfigContextFilterForm,
TenancyFilterForm,
ContactModelFilterForm,
NetBoxModelFilterSetForm
):
model = Device
fieldsets = (
(
None,
(
"q",
"filter_id",
),
),
(
None,
(
"group",
"save_coords",
"show_unconnected",
"show_cables",
"show_logical_connections",
"show_single_cable_logical_conns",
"show_neighbors",
"show_circuit",
"show_power",
"show_wireless",
),
),
(
None,
(
"tenant_group_id",
"tenant_id",
),
),
(None, ("region_id", "sitegroup_id", "site_id", "location_id", "rack_id")),
(
None,
(
"role_id",
"id",
"status",
),
),
(None, ("tag",)),
(None, ('q', 'filter_id', 'tag')),
(_('Options'), (
'group', 'save_coords', 'show_unconnected', 'show_cables', 'show_logical_connections',
'show_single_cable_logical_conns', 'show_neighbors', 'show_circuit', 'show_power', 'show_wireless',
)),
(_('Device'), ('device_id',)),
(_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
(_('Operation'), ('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address')),
(_('Hardware'), ('manufacturer_id', 'device_type_id', 'platform_id')),
(_('Tenant'), ('tenant_group_id', 'tenant_id')),
(_('Contacts'), ('contact', 'contact_role', 'contact_group')),
(_('Components'), (
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports',
)),
(_('Miscellaneous'), (
'has_primary_ip', 'has_oob_ip', 'virtual_chassis_member', 'config_template_id', 'local_context_data',
)),
)
group = forms.ModelChoiceField(
queryset=CoordinateGroup.objects.all(),
required=False,
label=_("Coordinate group"),
label=_('Coordinate group'),
)
device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False,
label=_('Device'),
query_params={
'location_id': '$location_id',
'region_id': '$region_id',
'site_group_id': '$site_group_id',
'site_id': '$site_id',
'role_id': '$role_id',
'contact': '$contact',
'contact_role': '$contact_role',
'contact_group': '$contact_group',
},
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
required=False,
label=_("Region")
label=_('Region')
)
role_id = DynamicModelMultipleChoiceField(
queryset=DeviceRole.objects.all(),
required=False,
label=_("Device Role")
)
id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
site_group_id = DynamicModelMultipleChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
label=_("Device"),
query_params={
"location_id": "$location_id",
"region_id": "$region_id",
"site_group_id": "$sitegroup_id",
"site_id": "$site_id",
"role_id": "$role_id",
},
label=_('Site Group'),
)
site_id = DynamicModelMultipleChoiceField(
queryset=Site.objects.all(),
required=False,
query_params={
"region_id": "$region_id",
"group_id": "$sitegroup_id",
'region_id': '$region_id',
'group_id': '$site_group_id',
},
label=_("Site"),
)
sitegroup_id = DynamicModelMultipleChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
label=_("Site Group"),
label=_('Site'),
)
location_id = DynamicModelMultipleChoiceField(
queryset=Location.objects.all(),
required=False,
query_params={
"region_id": "$region_id",
"site_group_id": "$sitegroup_id",
"site_id": "$site_id",
'region_id': '$region_id',
'site_group_id': '$site_group_id',
'site_id': '$site_id',
},
label=_("Location"),
label=_('Location'),
)
rack_id = DynamicModelMultipleChoiceField(
queryset=Rack.objects.all(),
required=False,
query_params={
"region_id": "$region_id",
"site_group_id": "$sitegroup_id",
"site_id": "$site_id",
"location_id": "$location_id",
'region_id': '$region_id',
'site_group_id': '$site_group_id',
'site_id': '$site_id',
'location_id': '$location_id',
},
label=_("Rack"),
label=_('Rack'),
)
status = forms.MultipleChoiceField(
choices=DeviceStatusChoices, required=False, label=_("Device Status")
choices=DeviceStatusChoices,
required=False,
label=_('Device Status')
)
role_id = DynamicModelMultipleChoiceField(
queryset=DeviceRole.objects.all(),
required=False,
label=_('Role')
)
airflow = forms.MultipleChoiceField(
label=_('Airflow'),
choices=add_blank_choice(DeviceAirflowChoices),
required=False
)
serial = forms.CharField(
label=_('Serial'),
required=False
)
asset_tag = forms.CharField(
label=_('Asset tag'),
required=False
)
mac_address = forms.CharField(
required=False,
label=_('MAC address')
)
manufacturer_id = DynamicModelMultipleChoiceField(
queryset=Manufacturer.objects.all(),
required=False,
label=_('Manufacturer')
)
device_type_id = DynamicModelMultipleChoiceField(
queryset=DeviceType.objects.all(),
required=False,
query_params={
'manufacturer_id': '$manufacturer_id'
},
label=_('Model')
)
platform_id = DynamicModelMultipleChoiceField(
queryset=Platform.objects.all(),
required=False,
null_option='None',
label=_('Platform')
)
console_ports = forms.NullBooleanField(
required=False,
label=_('Has console ports'),
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
console_server_ports = forms.NullBooleanField(
required=False,
label=_('Has console server ports'),
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
power_ports = forms.NullBooleanField(
required=False,
label=_('Has power ports'),
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
power_outlets = forms.NullBooleanField(
required=False,
label=_('Has power outlets'),
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
interfaces = forms.NullBooleanField(
required=False,
label=_('Has interfaces'),
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
pass_through_ports = forms.NullBooleanField(
required=False,
label=_('Has pass-through ports'),
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
config_template_id = DynamicModelMultipleChoiceField(
queryset=ConfigTemplate.objects.all(),
required=False,
label=_('Config template')
)
has_primary_ip = forms.NullBooleanField(
required=False,
label=_('Has a primary IP'),
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
has_oob_ip = forms.NullBooleanField(
required=False,
label='Has an OOB IP',
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
virtual_chassis_member = forms.NullBooleanField(
required=False,
label=_('Virtual chassis member'),
widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
tag = TagFilterField(model)
# options
save_coords = forms.BooleanField(
label=_("Save Coordinates"),
label=_('Save Coordinates'),
required=False,
disabled=(not settings.PLUGINS_CONFIG["netbox_topology_views"]["allow_coordinates_saving"] or settings.PLUGINS_CONFIG["netbox_topology_views"]["always_save_coordinates"]),
initial=(settings.PLUGINS_CONFIG["netbox_topology_views"]["always_save_coordinates"])
disabled=(not settings.PLUGINS_CONFIG['netbox_topology_views']['allow_coordinates_saving'] or settings.PLUGINS_CONFIG['netbox_topology_views']['always_save_coordinates']),
initial=(settings.PLUGINS_CONFIG['netbox_topology_views']['always_save_coordinates'])
)
show_unconnected = forms.BooleanField(
label=_("Show Unconnected"), required=False, initial=False
label=_('Show Unconnected'), required=False, initial=False
)
show_cables = forms.BooleanField(
label =_("Show Cables"), required=False, initial=False
label =_('Show Cables'), required=False, initial=False
)
show_logical_connections = forms.BooleanField(
label =_("Show Logical Connections"), required=False, initial=False
label =_('Show Logical Connections'), required=False, initial=False
)
show_single_cable_logical_conns = forms.BooleanField(
label =_("Show redundant Cable and Logical Connection"), required=False, initial=False
label =_('Show redundant Cable and Logical Connection'), required=False, initial=False
)
show_neighbors = forms.BooleanField(
label =_("Show Neighbors"), required=False, initial=False
label =_('Show Neighbors'), required=False, initial=False
)
show_circuit = forms.BooleanField(
label=_("Show Circuit Terminations"), required=False, initial=False
label=_('Show Circuit Terminations'), required=False, initial=False
)
show_power = forms.BooleanField(
label=_("Show Power Feeds"), required=False, initial=False
label=_('Show Power Feeds'), required=False, initial=False
)
show_wireless = forms.BooleanField(
label =_("Show Wireless Links"), required=False, initial=False
label =_('Show Wireless Links'), required=False, initial=False
)
class CoordinateGroupsForm(NetBoxModelForm):
@@ -220,20 +316,20 @@ class IndividualOptionsForm(NetBoxModelForm):
(
None,
(
"user_id",
"ignore_cable_type",
"preselected_device_roles",
"preselected_tags",
"save_coords",
"show_unconnected",
"show_cables",
"show_logical_connections",
"show_single_cable_logical_conns",
"show_neighbors",
"show_circuit",
"show_power",
"show_wireless",
"draw_default_layout",
'user_id',
'ignore_cable_type',
'preselected_device_roles',
'preselected_tags',
'save_coords',
'show_unconnected',
'show_cables',
'show_logical_connections',
'show_single_cable_logical_conns',
'show_neighbors',
'show_circuit',
'show_power',
'show_wireless',
'draw_default_layout',
),
),
)
@@ -241,105 +337,105 @@ class IndividualOptionsForm(NetBoxModelForm):
user_id = forms.CharField(widget=forms.HiddenInput())
ignore_cable_type = forms.MultipleChoiceField(
label=_("Ignore Termination Types"),
label=_('Ignore Termination Types'),
required=False,
choices=IndividualOptions.CHOICES,
help_text=_("Choose Termination Types that you want to be ignored. "
"If any ignored Termination Type is part of a connection, the "
"cable is not displayed.")
help_text=_('Choose Termination Types that you want to be ignored. '
'If any ignored Termination Type is part of a connection, the '
'cable is not displayed.')
)
preselected_device_roles = DynamicModelMultipleChoiceField(
label=_("Preselected Device Role"),
label=_('Preselected Device Role'),
queryset=DeviceRole.objects.all(),
required=False,
help_text=_("Select Device Roles that you want to have "
"preselected in the filter tab.")
help_text=_('Select Device Roles that you want to have '
'preselected in the filter tab.')
)
preselected_tags = forms.ModelMultipleChoiceField(
label=_("Preselected Tags"),
label=_('Preselected Tags'),
queryset=Device.tags.all(),
required=False,
help_text=_("Select Tags that you want to have "
"preselected in the filter tab.")
help_text=_('Select Tags that you want to have '
'preselected in the filter tab.')
)
save_coords = forms.BooleanField(
label=_("Save Coordinates"),
label=_('Save Coordinates'),
required=False,
initial=False,
help_text=_("Coordinates of nodes will be saved if dragged to a different "
"position. This option depends on parameters set in the config file. "
"It has no effect if 'allow_coordinates_saving' has not been set or "
" 'always_save_coordinates' has been set.")
help_text=_('Coordinates of nodes will be saved if dragged to a different '
'position. This option depends on parameters set in the config file. '
'It has no effect if \'allow_coordinates_saving\' has not been set or '
' \'always_save_coordinates\' has been set.')
)
show_unconnected = forms.BooleanField(
label=_("Show Unconnected"),
label=_('Show Unconnected'),
required=False,
initial=False,
help_text=_("Draws devices that have no connections or for which no "
"connection is displayed. This option depends on other parameters "
"like 'Show Cables' and 'Show Logical Connections'.")
help_text=_('Draws devices that have no connections or for which no '
'connection is displayed. This option depends on other parameters '
'like \'Show Cables\' and \'Show Logical Connections\'.')
)
show_cables = forms.BooleanField(
label =_("Show Cables"),
label =_('Show Cables'),
required=False,
initial=False,
help_text=_("Displays connections between interfaces that are connected "
"with one or more cables. These connections are displayed as solid "
"lines in the color of the cable.")
help_text=_('Displays connections between interfaces that are connected '
'with one or more cables. These connections are displayed as solid '
'lines in the color of the cable.')
)
show_logical_connections = forms.BooleanField(
label =_("Show Logical Connections"),
label =_('Show Logical Connections'),
required=False,
initial=False,
help_text=_("Displays connections between devices that are not "
"directly connected (e.g. via patch panels). These connections "
"are displayed as yellow dotted lines.")
help_text=_('Displays connections between devices that are not '
'directly connected (e.g. via patch panels). These connections '
'are displayed as yellow dotted lines.')
)
show_single_cable_logical_conns = forms.BooleanField(
label = ("Show redundant Cable and Logical Connection"),
label = ('Show redundant Cable and Logical Connection'),
required = False,
initial=False,
help_text=_("Shows a logical connection (in addition to a cable), "
"even if a cable is directly connected. Leaving this option "
"disabled prevents that redundant display. This option only "
"has an effect if 'Show Logical Connections' is activated.")
help_text=_('Shows a logical connection (in addition to a cable), '
'even if a cable is directly connected. Leaving this option '
'disabled prevents that redundant display. This option only '
'has an effect if \'Show Logical Connections\' is activated.')
)
show_neighbors = forms.BooleanField(
label =_("Show Neighbors"),
label =_('Show Neighbors'),
required=False,
initial=False,
help_text=_("Adds neighbors to the filter result set automatically. "
"Link peers will be added if 'Show Cables' is ticked, far-end "
"terminations will be added if 'Show Logical Connections' is ticked.")
help_text=_('Adds neighbors to the filter result set automatically. '
'Link peers will be added if \'Show Cables\' is ticked, far-end '
'terminations will be added if \'Show Logical Connections\' is ticked.')
)
show_circuit = forms.BooleanField(
label=_("Show Circuit Terminations"),
label=_('Show Circuit Terminations'),
required=False,
initial=False,
help_text=_("Displays connections between circuit terminations. "
"These connections are displayed as blue dashed lines.")
help_text=_('Displays connections between circuit terminations. '
'These connections are displayed as blue dashed lines.')
)
show_power = forms.BooleanField(
label=_("Show Power Feeds"),
label=_('Show Power Feeds'),
required=False,
initial=False,
help_text=_("Displays connections between power outlets and power "
"ports. These connections are displayed as solid lines in the "
"color of the cable. This option depends on 'Show Cables'.")
help_text=_('Displays connections between power outlets and power '
'ports. These connections are displayed as solid lines in the '
'color of the cable. This option depends on \'Show Cables\'.')
)
show_wireless = forms.BooleanField(
label =_("Show Wireless Links"),
label =_('Show Wireless Links'),
required=False,
initial=False,
help_text=_("Displays wireless connections. These connections are "
"displayed as blue dotted lines.")
help_text=_('Displays wireless connections. These connections are '
'displayed as blue dotted lines.')
)
draw_default_layout = forms.BooleanField(
label = ("Draw Default Layout"),
label = ('Draw Default Layout'),
required=False,
initial=False,
help_text=_("Enable this option if you want to draw the topology on "
"the initial load (when you go to the topology plugin page).")
help_text=_('Enable this option if you want to draw the topology on '
'the initial load (when you go to the topology plugin page).')
)
class Meta: