Fixes #16779: Fix saved filter selection for child object lists (#16789)

* Fixes #16779: Fix saved filter selection for child object lists

* Omit label_suffix
This commit is contained in:
Jeremy Stretch 2024-07-03 08:51:30 -04:00 committed by GitHub
parent 98748d901b
commit b18a6b7c59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 45 additions and 7 deletions

View File

@ -31,6 +31,7 @@ from utilities.views import (
GetRelatedModelsMixin, GetReturnURLMixin, ObjectPermissionRequiredMixin, ViewTab, register_model_view GetRelatedModelsMixin, GetReturnURLMixin, ObjectPermissionRequiredMixin, ViewTab, register_model_view
) )
from virtualization.filtersets import VirtualMachineFilterSet from virtualization.filtersets import VirtualMachineFilterSet
from virtualization.forms import VirtualMachineFilterForm
from virtualization.models import VirtualMachine from virtualization.models import VirtualMachine
from virtualization.tables import VirtualMachineTable from virtualization.tables import VirtualMachineTable
from . import filtersets, forms, tables from . import filtersets, forms, tables
@ -679,6 +680,7 @@ class RackRackReservationsView(generic.ObjectChildrenView):
child_model = RackReservation child_model = RackReservation
table = tables.RackReservationTable table = tables.RackReservationTable
filterset = filtersets.RackReservationFilterSet filterset = filtersets.RackReservationFilterSet
filterset_form = forms.RackReservationFilterForm
template_name = 'dcim/rack/reservations.html' template_name = 'dcim/rack/reservations.html'
tab = ViewTab( tab = ViewTab(
label=_('Reservations'), label=_('Reservations'),
@ -697,6 +699,7 @@ class RackNonRackedView(generic.ObjectChildrenView):
child_model = Device child_model = Device
table = tables.DeviceTable table = tables.DeviceTable
filterset = filtersets.DeviceFilterSet filterset = filtersets.DeviceFilterSet
filterset_form = forms.DeviceFilterForm
template_name = 'dcim/rack/non_racked_devices.html' template_name = 'dcim/rack/non_racked_devices.html'
tab = ViewTab( tab = ViewTab(
label=_('Non-Racked Devices'), label=_('Non-Racked Devices'),
@ -1835,6 +1838,7 @@ class DeviceConsolePortsView(DeviceComponentsView):
child_model = ConsolePort child_model = ConsolePort
table = tables.DeviceConsolePortTable table = tables.DeviceConsolePortTable
filterset = filtersets.ConsolePortFilterSet filterset = filtersets.ConsolePortFilterSet
filterset_form = forms.ConsolePortFilterForm
template_name = 'dcim/device/consoleports.html', template_name = 'dcim/device/consoleports.html',
tab = ViewTab( tab = ViewTab(
label=_('Console Ports'), label=_('Console Ports'),
@ -1850,6 +1854,7 @@ class DeviceConsoleServerPortsView(DeviceComponentsView):
child_model = ConsoleServerPort child_model = ConsoleServerPort
table = tables.DeviceConsoleServerPortTable table = tables.DeviceConsoleServerPortTable
filterset = filtersets.ConsoleServerPortFilterSet filterset = filtersets.ConsoleServerPortFilterSet
filterset_form = forms.ConsoleServerPortFilterForm
template_name = 'dcim/device/consoleserverports.html' template_name = 'dcim/device/consoleserverports.html'
tab = ViewTab( tab = ViewTab(
label=_('Console Server Ports'), label=_('Console Server Ports'),
@ -1865,6 +1870,7 @@ class DevicePowerPortsView(DeviceComponentsView):
child_model = PowerPort child_model = PowerPort
table = tables.DevicePowerPortTable table = tables.DevicePowerPortTable
filterset = filtersets.PowerPortFilterSet filterset = filtersets.PowerPortFilterSet
filterset_form = forms.PowerPortFilterForm
template_name = 'dcim/device/powerports.html' template_name = 'dcim/device/powerports.html'
tab = ViewTab( tab = ViewTab(
label=_('Power Ports'), label=_('Power Ports'),
@ -1880,6 +1886,7 @@ class DevicePowerOutletsView(DeviceComponentsView):
child_model = PowerOutlet child_model = PowerOutlet
table = tables.DevicePowerOutletTable table = tables.DevicePowerOutletTable
filterset = filtersets.PowerOutletFilterSet filterset = filtersets.PowerOutletFilterSet
filterset_form = forms.PowerOutletFilterForm
template_name = 'dcim/device/poweroutlets.html' template_name = 'dcim/device/poweroutlets.html'
tab = ViewTab( tab = ViewTab(
label=_('Power Outlets'), label=_('Power Outlets'),
@ -1895,6 +1902,7 @@ class DeviceInterfacesView(DeviceComponentsView):
child_model = Interface child_model = Interface
table = tables.DeviceInterfaceTable table = tables.DeviceInterfaceTable
filterset = filtersets.InterfaceFilterSet filterset = filtersets.InterfaceFilterSet
filterset_form = forms.InterfaceFilterForm
template_name = 'dcim/device/interfaces.html' template_name = 'dcim/device/interfaces.html'
tab = ViewTab( tab = ViewTab(
label=_('Interfaces'), label=_('Interfaces'),
@ -1916,6 +1924,7 @@ class DeviceFrontPortsView(DeviceComponentsView):
child_model = FrontPort child_model = FrontPort
table = tables.DeviceFrontPortTable table = tables.DeviceFrontPortTable
filterset = filtersets.FrontPortFilterSet filterset = filtersets.FrontPortFilterSet
filterset_form = forms.FrontPortFilterForm
template_name = 'dcim/device/frontports.html' template_name = 'dcim/device/frontports.html'
tab = ViewTab( tab = ViewTab(
label=_('Front Ports'), label=_('Front Ports'),
@ -1931,6 +1940,7 @@ class DeviceRearPortsView(DeviceComponentsView):
child_model = RearPort child_model = RearPort
table = tables.DeviceRearPortTable table = tables.DeviceRearPortTable
filterset = filtersets.RearPortFilterSet filterset = filtersets.RearPortFilterSet
filterset_form = forms.RearPortFilterForm
template_name = 'dcim/device/rearports.html' template_name = 'dcim/device/rearports.html'
tab = ViewTab( tab = ViewTab(
label=_('Rear Ports'), label=_('Rear Ports'),
@ -1946,6 +1956,7 @@ class DeviceModuleBaysView(DeviceComponentsView):
child_model = ModuleBay child_model = ModuleBay
table = tables.DeviceModuleBayTable table = tables.DeviceModuleBayTable
filterset = filtersets.ModuleBayFilterSet filterset = filtersets.ModuleBayFilterSet
filterset_form = forms.ModuleBayFilterForm
template_name = 'dcim/device/modulebays.html' template_name = 'dcim/device/modulebays.html'
actions = { actions = {
**DEFAULT_ACTION_PERMISSIONS, **DEFAULT_ACTION_PERMISSIONS,
@ -1965,6 +1976,7 @@ class DeviceDeviceBaysView(DeviceComponentsView):
child_model = DeviceBay child_model = DeviceBay
table = tables.DeviceDeviceBayTable table = tables.DeviceDeviceBayTable
filterset = filtersets.DeviceBayFilterSet filterset = filtersets.DeviceBayFilterSet
filterset_form = forms.DeviceBayFilterForm
template_name = 'dcim/device/devicebays.html' template_name = 'dcim/device/devicebays.html'
actions = { actions = {
**DEFAULT_ACTION_PERMISSIONS, **DEFAULT_ACTION_PERMISSIONS,
@ -1984,6 +1996,7 @@ class DeviceInventoryView(DeviceComponentsView):
child_model = InventoryItem child_model = InventoryItem
table = tables.DeviceInventoryItemTable table = tables.DeviceInventoryItemTable
filterset = filtersets.InventoryItemFilterSet filterset = filtersets.InventoryItemFilterSet
filterset_form = forms.InventoryItemFilterForm
template_name = 'dcim/device/inventory.html' template_name = 'dcim/device/inventory.html'
actions = { actions = {
**DEFAULT_ACTION_PERMISSIONS, **DEFAULT_ACTION_PERMISSIONS,
@ -2062,6 +2075,7 @@ class DeviceVirtualMachinesView(generic.ObjectChildrenView):
child_model = VirtualMachine child_model = VirtualMachine
table = VirtualMachineTable table = VirtualMachineTable
filterset = VirtualMachineFilterSet filterset = VirtualMachineFilterSet
filterset_form = VirtualMachineFilterForm
tab = ViewTab( tab = ViewTab(
label=_('Virtual Machines'), label=_('Virtual Machines'),
badge=lambda obj: VirtualMachine.objects.filter(cluster=obj.cluster, device=obj).count(), badge=lambda obj: VirtualMachine.objects.filter(cluster=obj.cluster, device=obj).count(),
@ -2944,6 +2958,7 @@ class InventoryItemChildrenView(generic.ObjectChildrenView):
child_model = InventoryItem child_model = InventoryItem
table = tables.InventoryItemTable table = tables.InventoryItemTable
filterset = filtersets.InventoryItemFilterSet filterset = filtersets.InventoryItemFilterSet
filterset_form = forms.InventoryItemFilterForm
tab = ViewTab( tab = ViewTab(
label=_('Children'), label=_('Children'),
badge=lambda obj: obj.child_items.count(), badge=lambda obj: obj.child_items.count(),

View File

@ -7,6 +7,7 @@ from django.utils.translation import gettext as _
from circuits.models import Provider from circuits.models import Provider
from dcim.filtersets import InterfaceFilterSet from dcim.filtersets import InterfaceFilterSet
from dcim.forms import InterfaceFilterForm
from dcim.models import Interface, Site from dcim.models import Interface, Site
from netbox.views import generic from netbox.views import generic
from tenancy.views import ObjectContactsView from tenancy.views import ObjectContactsView
@ -14,6 +15,7 @@ from utilities.query import count_related
from utilities.tables import get_table_ordering from utilities.tables import get_table_ordering
from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
from virtualization.filtersets import VMInterfaceFilterSet from virtualization.filtersets import VMInterfaceFilterSet
from virtualization.forms import VMInterfaceFilterForm
from virtualization.models import VMInterface from virtualization.models import VMInterface
from . import filtersets, forms, tables from . import filtersets, forms, tables
from .choices import PrefixStatusChoices from .choices import PrefixStatusChoices
@ -206,6 +208,7 @@ class ASNRangeASNsView(generic.ObjectChildrenView):
child_model = ASN child_model = ASN
table = tables.ASNTable table = tables.ASNTable
filterset = filtersets.ASNFilterSet filterset = filtersets.ASNFilterSet
filterset_form = forms.ASNFilterForm
tab = ViewTab( tab = ViewTab(
label=_('ASNs'), label=_('ASNs'),
badge=lambda x: x.get_child_asns().count(), badge=lambda x: x.get_child_asns().count(),
@ -337,6 +340,7 @@ class AggregatePrefixesView(generic.ObjectChildrenView):
child_model = Prefix child_model = Prefix
table = tables.PrefixTable table = tables.PrefixTable
filterset = filtersets.PrefixFilterSet filterset = filtersets.PrefixFilterSet
filterset_form = forms.PrefixFilterForm
template_name = 'ipam/aggregate/prefixes.html' template_name = 'ipam/aggregate/prefixes.html'
tab = ViewTab( tab = ViewTab(
label=_('Prefixes'), label=_('Prefixes'),
@ -523,6 +527,7 @@ class PrefixPrefixesView(generic.ObjectChildrenView):
child_model = Prefix child_model = Prefix
table = tables.PrefixTable table = tables.PrefixTable
filterset = filtersets.PrefixFilterSet filterset = filtersets.PrefixFilterSet
filterset_form = forms.PrefixFilterForm
template_name = 'ipam/prefix/prefixes.html' template_name = 'ipam/prefix/prefixes.html'
tab = ViewTab( tab = ViewTab(
label=_('Child Prefixes'), label=_('Child Prefixes'),
@ -558,6 +563,7 @@ class PrefixIPRangesView(generic.ObjectChildrenView):
child_model = IPRange child_model = IPRange
table = tables.IPRangeTable table = tables.IPRangeTable
filterset = filtersets.IPRangeFilterSet filterset = filtersets.IPRangeFilterSet
filterset_form = forms.IPRangeFilterForm
template_name = 'ipam/prefix/ip_ranges.html' template_name = 'ipam/prefix/ip_ranges.html'
tab = ViewTab( tab = ViewTab(
label=_('Child Ranges'), label=_('Child Ranges'),
@ -584,6 +590,7 @@ class PrefixIPAddressesView(generic.ObjectChildrenView):
child_model = IPAddress child_model = IPAddress
table = tables.IPAddressTable table = tables.IPAddressTable
filterset = filtersets.IPAddressFilterSet filterset = filtersets.IPAddressFilterSet
filterset_form = forms.IPAddressFilterForm
template_name = 'ipam/prefix/ip_addresses.html' template_name = 'ipam/prefix/ip_addresses.html'
tab = ViewTab( tab = ViewTab(
label=_('IP Addresses'), label=_('IP Addresses'),
@ -683,6 +690,7 @@ class IPRangeIPAddressesView(generic.ObjectChildrenView):
child_model = IPAddress child_model = IPAddress
table = tables.IPAddressTable table = tables.IPAddressTable
filterset = filtersets.IPAddressFilterSet filterset = filtersets.IPAddressFilterSet
filterset_form = forms.IPRangeFilterForm
template_name = 'ipam/iprange/ip_addresses.html' template_name = 'ipam/iprange/ip_addresses.html'
tab = ViewTab( tab = ViewTab(
label=_('IP Addresses'), label=_('IP Addresses'),
@ -885,6 +893,7 @@ class IPAddressRelatedIPsView(generic.ObjectChildrenView):
child_model = IPAddress child_model = IPAddress
table = tables.IPAddressTable table = tables.IPAddressTable
filterset = filtersets.IPAddressFilterSet filterset = filtersets.IPAddressFilterSet
filterset_form = forms.IPAddressFilterForm
tab = ViewTab( tab = ViewTab(
label=_('Related IPs'), label=_('Related IPs'),
badge=lambda x: x.get_related_ips().count(), badge=lambda x: x.get_related_ips().count(),
@ -957,6 +966,7 @@ class VLANGroupVLANsView(generic.ObjectChildrenView):
child_model = VLAN child_model = VLAN
table = tables.VLANTable table = tables.VLANTable
filterset = filtersets.VLANFilterSet filterset = filtersets.VLANFilterSet
filterset_form = forms.VLANFilterForm
tab = ViewTab( tab = ViewTab(
label=_('VLANs'), label=_('VLANs'),
badge=lambda x: x.get_child_vlans().count(), badge=lambda x: x.get_child_vlans().count(),
@ -1112,6 +1122,7 @@ class VLANInterfacesView(generic.ObjectChildrenView):
child_model = Interface child_model = Interface
table = tables.VLANDevicesTable table = tables.VLANDevicesTable
filterset = InterfaceFilterSet filterset = InterfaceFilterSet
filterset_form = InterfaceFilterForm
tab = ViewTab( tab = ViewTab(
label=_('Device Interfaces'), label=_('Device Interfaces'),
badge=lambda x: x.get_interfaces().count(), badge=lambda x: x.get_interfaces().count(),
@ -1129,6 +1140,7 @@ class VLANVMInterfacesView(generic.ObjectChildrenView):
child_model = VMInterface child_model = VMInterface
table = tables.VLANVirtualMachinesTable table = tables.VLANVirtualMachinesTable
filterset = VMInterfaceFilterSet filterset = VMInterfaceFilterSet
filterset_form = VMInterfaceFilterForm
tab = ViewTab( tab = ViewTab(
label=_('VM Interfaces'), label=_('VM Interfaces'),
badge=lambda x: x.get_vminterfaces().count(), badge=lambda x: x.get_vminterfaces().count(),

View File

@ -176,7 +176,7 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
'model': model, 'model': model,
'table': table, 'table': table,
'actions': actions, 'actions': actions,
'filter_form': self.filterset_form(request.GET, label_suffix='') if self.filterset_form else None, 'filter_form': self.filterset_form(request.GET) if self.filterset_form else None,
'prerequisite_model': get_prerequisite_model(self.queryset), 'prerequisite_model': get_prerequisite_model(self.queryset),
**self.get_extra_context(request), **self.get_extra_context(request),
} }

View File

@ -87,12 +87,14 @@ class ObjectChildrenView(ObjectView, ActionsMixin, TableMixin):
child_model: The model class which represents the child objects child_model: The model class which represents the child objects
table: The django-tables2 Table class used to render the child objects list table: The django-tables2 Table class used to render the child objects list
filterset: A django-filter FilterSet that is applied to the queryset filterset: A django-filter FilterSet that is applied to the queryset
filterset_form: The form class used to render filter options
actions: A mapping of supported actions to their required permissions. When adding custom actions, bulk actions: A mapping of supported actions to their required permissions. When adding custom actions, bulk
action names must be prefixed with `bulk_`. (See ActionsMixin.) action names must be prefixed with `bulk_`. (See ActionsMixin.)
""" """
child_model = None child_model = None
table = None table = None
filterset = None filterset = None
filterset_form = None
template_name = 'generic/object_children.html' template_name = 'generic/object_children.html'
def get_children(self, request, parent): def get_children(self, request, parent):
@ -152,6 +154,7 @@ class ObjectChildrenView(ObjectView, ActionsMixin, TableMixin):
'base_template': f'{instance._meta.app_label}/{instance._meta.model_name}.html', 'base_template': f'{instance._meta.app_label}/{instance._meta.model_name}.html',
'table': table, 'table': table,
'table_config': f'{table.name}_config', 'table_config': f'{table.name}_config',
'filter_form': self.filterset_form(request.GET) if self.filterset_form else None,
'actions': actions, 'actions': actions,
'tab': self.tab, 'tab': self.tab,
'return_url': request.get_full_path(), 'return_url': request.get_full_path(),

View File

@ -13,14 +13,16 @@
</div> </div>
</div> </div>
<div class="col-auto d-print-none"> {% if filter_form %}
<div class="input-group"> <div class="col-auto d-print-none">
<div class="input-group-text"> <div class="input-group">
<i class="mdi mdi-filter" title="{% trans "Saved filter" %}"></i> <div class="input-group-text">
<i class="mdi mdi-filter" title="{% trans "Saved filter" %}"></i>
</div>
{{ filter_form.filter_id }}
</div> </div>
{{ filter_form.filter_id }}
</div> </div>
</div> {% endif %}
<div class="col-auto ms-auto d-print-none"> <div class="col-auto ms-auto d-print-none">
{% if request.user.is_authenticated and table_modal %} {% if request.user.is_authenticated and table_modal %}

View File

@ -13,6 +13,7 @@ class ObjectContactsView(generic.ObjectChildrenView):
child_model = ContactAssignment child_model = ContactAssignment
table = tables.ContactAssignmentTable table = tables.ContactAssignmentTable
filterset = filtersets.ContactAssignmentFilterSet filterset = filtersets.ContactAssignmentFilterSet
filterset_form = forms.ContactAssignmentFilterForm
template_name = 'tenancy/object_contacts.html' template_name = 'tenancy/object_contacts.html'
tab = ViewTab( tab = ViewTab(
label=_('Contacts'), label=_('Contacts'),

View File

@ -10,6 +10,7 @@ from django.utils.translation import gettext as _
from jinja2.exceptions import TemplateError from jinja2.exceptions import TemplateError
from dcim.filtersets import DeviceFilterSet from dcim.filtersets import DeviceFilterSet
from dcim.forms import DeviceFilterForm
from dcim.models import Device from dcim.models import Device
from dcim.tables import DeviceTable from dcim.tables import DeviceTable
from extras.views import ObjectConfigContextView from extras.views import ObjectConfigContextView
@ -173,6 +174,7 @@ class ClusterVirtualMachinesView(generic.ObjectChildrenView):
child_model = VirtualMachine child_model = VirtualMachine
table = tables.VirtualMachineTable table = tables.VirtualMachineTable
filterset = filtersets.VirtualMachineFilterSet filterset = filtersets.VirtualMachineFilterSet
filterset_form = forms.VirtualMachineFilterForm
tab = ViewTab( tab = ViewTab(
label=_('Virtual Machines'), label=_('Virtual Machines'),
badge=lambda obj: obj.virtual_machines.count(), badge=lambda obj: obj.virtual_machines.count(),
@ -190,6 +192,7 @@ class ClusterDevicesView(generic.ObjectChildrenView):
child_model = Device child_model = Device
table = DeviceTable table = DeviceTable
filterset = DeviceFilterSet filterset = DeviceFilterSet
filterset_form = DeviceFilterForm
template_name = 'virtualization/cluster/devices.html' template_name = 'virtualization/cluster/devices.html'
actions = { actions = {
'add': {'add'}, 'add': {'add'},
@ -350,6 +353,7 @@ class VirtualMachineInterfacesView(generic.ObjectChildrenView):
child_model = VMInterface child_model = VMInterface
table = tables.VirtualMachineVMInterfaceTable table = tables.VirtualMachineVMInterfaceTable
filterset = filtersets.VMInterfaceFilterSet filterset = filtersets.VMInterfaceFilterSet
filterset_form = forms.VMInterfaceFilterForm
template_name = 'virtualization/virtualmachine/interfaces.html' template_name = 'virtualization/virtualmachine/interfaces.html'
actions = { actions = {
**DEFAULT_ACTION_PERMISSIONS, **DEFAULT_ACTION_PERMISSIONS,
@ -375,6 +379,7 @@ class VirtualMachineVirtualDisksView(generic.ObjectChildrenView):
child_model = VirtualDisk child_model = VirtualDisk
table = tables.VirtualMachineVirtualDiskTable table = tables.VirtualMachineVirtualDiskTable
filterset = filtersets.VirtualDiskFilterSet filterset = filtersets.VirtualDiskFilterSet
filterset_form = forms.VirtualDiskFilterForm
template_name = 'virtualization/virtualmachine/virtual_disks.html' template_name = 'virtualization/virtualmachine/virtual_disks.html'
tab = ViewTab( tab = ViewTab(
label=_('Virtual Disks'), label=_('Virtual Disks'),