mirror of
https://github.com/netbox-community/netbox.git
synced 2026-02-06 07:16:25 -06:00
Fixes #7604: Add filter modifier dropdowns for advanced lookup operators
Implements dynamic filter modifier UI that allows users to select lookup operators (exact, contains, starts with, regex, negation, empty/not empty) directly in filter forms without manual URL parameter editing. Supports filters for all scalar types and strings, as well as some related object filters. Explicitly does not support filters on fields that use APIWidget. That has been broken out in to follow up work. **Backend:** - FilterModifierWidget: Wraps form widgets with lookup modifier dropdown - FilterModifierMixin: Auto-enhances filterset fields with appropriate lookups - Extended lookup support: Adds negation (n), regex, iregex, empty_true/false lookups - Field-type-aware: CharField gets text lookups, IntegerField gets comparison operators, etc. **Frontend:** - TypeScript handler syncs modifier dropdown with URL parameters - Dynamically updates form field names (serial → serial__ic) on modifier change - Flexible-width modifier dropdowns with semantic CSS classes
This commit is contained in:
@@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dcim.choices import *
|
||||
from dcim.constants import *
|
||||
from dcim.filtersets import DeviceFilterSet, RackFilterSet, PowerOutletFilterSet
|
||||
from dcim.models import *
|
||||
from extras.forms import LocalConfigContextFilterForm
|
||||
from extras.models import ConfigTemplate
|
||||
@@ -16,6 +17,8 @@ from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
|
||||
from users.models import Owner, User
|
||||
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
|
||||
from utilities.forms.fields import ColorField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField
|
||||
from utilities.forms.filterset_mappings import FILTERSET_MAPPINGS
|
||||
from utilities.forms.mixins import FilterModifierMixin
|
||||
from utilities.forms.rendering import FieldSet
|
||||
from utilities.forms.widgets import NumberWithOptions
|
||||
from virtualization.models import Cluster, ClusterGroup, VirtualMachine
|
||||
@@ -330,7 +333,7 @@ class RackTypeFilterForm(RackBaseFilterForm):
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, RackBaseFilterForm):
|
||||
class RackFilterForm(FilterModifierMixin, TenancyFilterForm, ContactModelFilterForm, RackBaseFilterForm):
|
||||
model = Rack
|
||||
fieldsets = (
|
||||
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
|
||||
@@ -778,6 +781,7 @@ class PlatformFilterForm(NestedGroupModelFilterSetForm):
|
||||
|
||||
|
||||
class DeviceFilterForm(
|
||||
FilterModifierMixin,
|
||||
LocalConfigContextFilterForm,
|
||||
TenancyFilterForm,
|
||||
ContactModelFilterForm,
|
||||
@@ -1420,7 +1424,7 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
||||
class PowerOutletFilterForm(FilterModifierMixin, PathEndpointFilterForm, DeviceComponentFilterForm):
|
||||
model = PowerOutlet
|
||||
fieldsets = (
|
||||
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
|
||||
@@ -1830,3 +1834,9 @@ class InterfaceConnectionFilterForm(FilterForm):
|
||||
},
|
||||
label=_('Device')
|
||||
)
|
||||
|
||||
|
||||
# Register FilterSet mappings for FilterModifierMixin lookup verification
|
||||
FILTERSET_MAPPINGS[DeviceFilterForm] = DeviceFilterSet
|
||||
FILTERSET_MAPPINGS[RackFilterForm] = RackFilterSet
|
||||
FILTERSET_MAPPINGS[PowerOutletFilterForm] = PowerOutletFilterSet
|
||||
|
||||
Reference in New Issue
Block a user