Compare commits

...

3 Commits

Author SHA1 Message Date
Jeremy Stretch
5bf34b0c32 Reorder import statements 2025-12-05 14:28:13 -05:00
Jeremy Stretch
0319fd599a Add register_filterset() to plugins documentation for filtersets 2025-12-05 14:22:45 -05:00
Jeremy Stretch
6c94d8d49b Move register_filterset() back to utilities.filtersets 2025-12-05 14:15:52 -05:00
14 changed files with 42 additions and 28 deletions

View File

@@ -6,12 +6,17 @@ Filter sets define the mechanisms available for filtering or searching through a
To support additional functionality standard to NetBox models, such as tag assignment and custom field support, the `NetBoxModelFilterSet` class is available for use by plugins. This should be used as the base filter set class for plugin models which inherit from `NetBoxModel`. Within this class, individual filters can be declared as directed by the `django-filters` documentation. An example is provided below. To support additional functionality standard to NetBox models, such as tag assignment and custom field support, the `NetBoxModelFilterSet` class is available for use by plugins. This should be used as the base filter set class for plugin models which inherit from `NetBoxModel`. Within this class, individual filters can be declared as directed by the `django-filters` documentation. An example is provided below.
!!! info "New in NetBox v4.5: FilterSet Registration"
NetBox v4.5 introduced the `register_filterset()` utility function. This enables plugins to register their filtersets to receive advanced functionality, such as the automatic attachment of field-specific lookup modifiers on the filter form. Registration is optional: Unregistered filtersets will continue to work as before, but will not receive the enhanced functionality.
```python ```python
# filtersets.py # filtersets.py
import django_filters import django_filters
from netbox.filtersets import NetBoxModelFilterSet from netbox.filtersets import NetBoxModelFilterSet
from utilities.filtersets import register_filterset
from .models import MyModel from .models import MyModel
@register_filterset
class MyFilterSet(NetBoxModelFilterSet): class MyFilterSet(NetBoxModelFilterSet):
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=( choices=(
@@ -62,7 +67,9 @@ The `ObjectListView` has a field called Quick Search. For Quick Search to work t
```python ```python
from django.db.models import Q from django.db.models import Q
from netbox.filtersets import NetBoxModelFilterSet from netbox.filtersets import NetBoxModelFilterSet
from utilities.filtersets import register_filterset
@register_filterset
class MyFilterSet(NetBoxModelFilterSet): class MyFilterSet(NetBoxModelFilterSet):
... ...
def search(self, queryset, name, value): def search(self, queryset, name, value):
@@ -90,7 +97,9 @@ This class filters `tags` using the `slug` field. For example:
```python ```python
from django_filters import FilterSet from django_filters import FilterSet
from extras.filters import TagFilter from extras.filters import TagFilter
from utilities.filtersets import register_filterset
@register_filterset
class MyModelFilterSet(FilterSet): class MyModelFilterSet(FilterSet):
tag = TagFilter() tag = TagFilter()
``` ```
@@ -106,7 +115,9 @@ This class filters `tags` using the `id` field. For example:
```python ```python
from django_filters import FilterSet from django_filters import FilterSet
from extras.filters import TagIDFilter from extras.filters import TagIDFilter
from utilities.filtersets import register_filterset
@register_filterset
class MyModelFilterSet(FilterSet): class MyModelFilterSet(FilterSet):
tag_id = TagIDFilter() tag_id = TagIDFilter()
``` ```

View File

@@ -7,11 +7,11 @@ from dcim.filtersets import CabledObjectFilterSet
from dcim.models import Interface, Location, Region, Site, SiteGroup from dcim.models import Interface, Location, Region, Site, SiteGroup
from ipam.models import ASN from ipam.models import ASN
from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet
from netbox.plugins.registration import register_filterset
from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
from utilities.filters import ( from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, TreeNodeMultipleChoiceFilter, ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, TreeNodeMultipleChoiceFilter,
) )
from utilities.filtersets import register_filterset
from .choices import * from .choices import *
from .models import * from .models import *

View File

@@ -4,10 +4,10 @@ from django.db.models import Q
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, PrimaryModelFilterSet from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, PrimaryModelFilterSet
from netbox.plugins.registration import register_filterset
from netbox.utils import get_data_backend_choices from netbox.utils import get_data_backend_choices
from users.models import User from users.models import User
from utilities.filters import ContentTypeFilter from utilities.filters import ContentTypeFilter
from utilities.filtersets import register_filterset
from .choices import * from .choices import *
from .models import * from .models import *

View File

@@ -14,7 +14,6 @@ from netbox.filtersets import (
AttributeFiltersMixin, BaseFilterSet, ChangeLoggedModelFilterSet, NestedGroupModelFilterSet, AttributeFiltersMixin, BaseFilterSet, ChangeLoggedModelFilterSet, NestedGroupModelFilterSet,
OrganizationalModelFilterSet, PrimaryModelFilterSet, NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet, NetBoxModelFilterSet,
) )
from netbox.plugins.registration import register_filterset
from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
from tenancy.models import * from tenancy.models import *
from users.filterset_mixins import OwnerFilterMixin from users.filterset_mixins import OwnerFilterMixin
@@ -23,6 +22,7 @@ from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueWWNFilter, ContentTypeFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueWWNFilter,
NumericArrayFilter, TreeNodeMultipleChoiceFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter,
) )
from utilities.filtersets import register_filterset
from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface
from vpn.models import L2VPN from vpn.models import L2VPN
from wireless.choices import WirelessChannelChoices, WirelessRoleChoices from wireless.choices import WirelessChannelChoices, WirelessRoleChoices

View File

@@ -6,13 +6,13 @@ from django.utils.translation import gettext as _
from core.models import DataSource, ObjectType from core.models import DataSource, ObjectType
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet, PrimaryModelFilterSet from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet, PrimaryModelFilterSet
from netbox.plugins.registration import register_filterset
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from users.filterset_mixins import OwnerFilterMixin from users.filterset_mixins import OwnerFilterMixin
from users.models import Group, User from users.models import Group, User
from utilities.filters import ( from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter
) )
from utilities.filtersets import register_filterset
from virtualization.models import Cluster, ClusterGroup, ClusterType from virtualization.models import Cluster, ClusterGroup, ClusterType
from .choices import * from .choices import *
from .filters import TagFilter, TagIDFilter from .filters import TagFilter, TagIDFilter

View File

@@ -1,6 +1,5 @@
import django_filters import django_filters
import netaddr import netaddr
from dcim.base_filtersets import ScopedFilterSet
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Q from django.db.models import Q
@@ -10,15 +9,16 @@ from drf_spectacular.utils import extend_schema_field
from netaddr.core import AddrFormatError from netaddr.core import AddrFormatError
from circuits.models import Provider from circuits.models import Provider
from dcim.base_filtersets import ScopedFilterSet
from dcim.models import Device, Interface, Region, Site, SiteGroup from dcim.models import Device, Interface, Region, Site, SiteGroup
from netbox.filtersets import ( from netbox.filtersets import (
ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet, PrimaryModelFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet, PrimaryModelFilterSet,
) )
from netbox.plugins.registration import register_filterset
from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
from utilities.filters import ( from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter, ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter,
) )
from utilities.filtersets import register_filterset
from virtualization.models import VirtualMachine, VMInterface from virtualization.models import VirtualMachine, VMInterface
from vpn.models import L2VPN from vpn.models import L2VPN
from .choices import * from .choices import *

View File

@@ -7,7 +7,6 @@ from .navigation import PluginMenu, PluginMenuButton, PluginMenuItem
from .templates import PluginTemplateExtension from .templates import PluginTemplateExtension
__all__ = ( __all__ = (
'register_filterset',
'register_graphql_schema', 'register_graphql_schema',
'register_menu', 'register_menu',
'register_menu_items', 'register_menu_items',
@@ -45,18 +44,6 @@ def register_template_extensions(class_list):
registry['plugins']['template_extensions'][model].append(template_extension) registry['plugins']['template_extensions'][model].append(template_extension)
def register_filterset(filterset_class):
"""
Decorator for registering a FilterSet with the application registry.
Uses model identifier as key to match search index pattern.
"""
model = filterset_class._meta.model
label = f'{model._meta.app_label}.{model._meta.model_name}'
registry['filtersets'][label] = filterset_class
return filterset_class
def register_menu(menu): def register_menu(menu):
if not isinstance(menu, PluginMenu): if not isinstance(menu, PluginMenu):
raise TypeError(_("{item} must be an instance of netbox.plugins.PluginMenuItem").format(item=menu)) raise TypeError(_("{item} must be an instance of netbox.plugins.PluginMenuItem").format(item=menu))

View File

@@ -5,8 +5,8 @@ from django.utils.translation import gettext as _
from netbox.filtersets import ( from netbox.filtersets import (
NestedGroupModelFilterSet, NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet, NestedGroupModelFilterSet, NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet,
) )
from netbox.plugins.registration import register_filterset
from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter
from utilities.filtersets import register_filterset
from .models import * from .models import *
__all__ = ( __all__ = (

View File

@@ -1,14 +1,13 @@
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from core.models import ObjectType from core.models import ObjectType
from extras.models import NotificationGroup from extras.models import NotificationGroup
from netbox.filtersets import BaseFilterSet from netbox.filtersets import BaseFilterSet
from netbox.plugins.registration import register_filterset
from users.models import Group, ObjectPermission, Owner, OwnerGroup, Token, User from users.models import Group, ObjectPermission, Owner, OwnerGroup, Token, User
from utilities.filters import ContentTypeFilter from utilities.filters import ContentTypeFilter
from utilities.filtersets import register_filterset
__all__ = ( __all__ = (
'GroupFilterSet', 'GroupFilterSet',

View File

@@ -0,0 +1,17 @@
from netbox.registry import registry
__all__ = (
'register_filterset',
)
def register_filterset(filterset_class):
"""
Decorator for registering a FilterSet with the application registry.
Uses model identifier as key to match search index pattern.
"""
model = filterset_class._meta.model
label = f'{model._meta.app_label}.{model._meta.model_name}'
registry['filtersets'][label] = filterset_class
return filterset_class

View File

@@ -8,7 +8,7 @@ import dcim.filtersets # noqa: F401 - Import to register Device filterset
from dcim.forms.filtersets import DeviceFilterForm from dcim.forms.filtersets import DeviceFilterForm
from dcim.models import Device from dcim.models import Device
from netbox.filtersets import BaseFilterSet from netbox.filtersets import BaseFilterSet
from netbox.plugins.registration import register_filterset from utilities.filtersets import register_filterset
from users.models import User from users.models import User
from utilities.forms.fields import TagFilterField from utilities.forms.fields import TagFilterField
from utilities.forms.mixins import FilterModifierMixin from utilities.forms.mixins import FilterModifierMixin

View File

@@ -10,10 +10,10 @@ from extras.filtersets import LocalConfigContextFilterSet
from extras.models import ConfigTemplate from extras.models import ConfigTemplate
from ipam.filtersets import PrimaryIPFilterSet from ipam.filtersets import PrimaryIPFilterSet
from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet
from netbox.plugins.registration import register_filterset
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
from users.filterset_mixins import OwnerFilterMixin from users.filterset_mixins import OwnerFilterMixin
from utilities.filters import MultiValueCharFilter, MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter from utilities.filters import MultiValueCharFilter, MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter
from utilities.filtersets import register_filterset
from .choices import * from .choices import *
from .models import * from .models import *

View File

@@ -6,9 +6,9 @@ from core.models import ObjectType
from dcim.models import Device, Interface from dcim.models import Device, Interface
from ipam.models import IPAddress, RouteTarget, VLAN from ipam.models import IPAddress, RouteTarget, VLAN
from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet
from netbox.plugins.registration import register_filterset
from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
from utilities.filters import ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter from utilities.filters import ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter
from utilities.filtersets import register_filterset
from virtualization.models import VirtualMachine, VMInterface from virtualization.models import VirtualMachine, VMInterface
from .choices import * from .choices import *
from .models import * from .models import *

View File

@@ -1,14 +1,14 @@
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from dcim.choices import LinkStatusChoices
from dcim.base_filtersets import ScopedFilterSet from dcim.base_filtersets import ScopedFilterSet
from dcim.choices import LinkStatusChoices
from dcim.models import Interface from dcim.models import Interface
from ipam.models import VLAN from ipam.models import VLAN
from netbox.filtersets import NestedGroupModelFilterSet, PrimaryModelFilterSet from netbox.filtersets import NestedGroupModelFilterSet, PrimaryModelFilterSet
from netbox.plugins.registration import register_filterset
from tenancy.filtersets import TenancyFilterSet from tenancy.filtersets import TenancyFilterSet
from utilities.filters import TreeNodeMultipleChoiceFilter from utilities.filters import TreeNodeMultipleChoiceFilter
from utilities.filtersets import register_filterset
from .choices import * from .choices import *
from .models import * from .models import *