Fixes: #18579 Add contact filters to services (#18818)

* Add Contact filter to Services

* Add ContactModelFilterForm to ProviderAccountFilterForm

* Add Contact filter support for Aggregate

* Add Contact filter support for Prefix

* Add Contact filter to IPRange

* Add Contact filter to IPAddress

* Add Contact filter to L2VPN

* Add Contact filter to TunnelGroup

* Add Contact filter to Tunnel

* Add ContactModelFilterSet to ProviderAccountFilterSet

* Fixes classes inheritance order

Setup NetBoxModelFilterSetForm as the last inherited class

Co-authored-by: Jason Novinger <jnovinger@gmail.com>

---------

Co-authored-by: Jason Novinger <jnovinger@gmail.com>
This commit is contained in:
Renato Almeida de Oliveira 2025-03-06 12:41:41 -03:00 committed by GitHub
parent 2d35cc56ed
commit 3ef7ab4416
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 35 additions and 22 deletions

View File

@ -95,7 +95,7 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
) )
class ProviderAccountFilterSet(NetBoxModelFilterSet): class ProviderAccountFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter( provider_id = django_filters.ModelMultipleChoiceFilter(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
label=_('Provider (ID)'), label=_('Provider (ID)'),

View File

@ -66,11 +66,12 @@ class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class ProviderAccountFilterForm(NetBoxModelFilterSetForm): class ProviderAccountFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
model = ProviderAccount model = ProviderAccount
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
FieldSet('provider_id', 'account', name=_('Attributes')), FieldSet('provider_id', 'account', name=_('Attributes')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
provider_id = DynamicModelMultipleChoiceField( provider_id = DynamicModelMultipleChoiceField(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),

View File

@ -12,7 +12,8 @@ from netaddr.core import AddrFormatError
from circuits.models import Provider from circuits.models import Provider
from dcim.models import Device, Interface, Region, Site, SiteGroup from dcim.models import Device, Interface, Region, Site, SiteGroup
from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet
from tenancy.filtersets import 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,
) )
@ -148,7 +149,7 @@ class RIRFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'is_private', 'description') fields = ('id', 'name', 'slug', 'is_private', 'description')
class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
family = django_filters.NumberFilter( family = django_filters.NumberFilter(
field_name='prefix', field_name='prefix',
lookup_expr='family' lookup_expr='family'
@ -276,7 +277,7 @@ class RoleFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'description', 'weight') fields = ('id', 'name', 'slug', 'description', 'weight')
class PrefixFilterSet(NetBoxModelFilterSet, ScopedFilterSet, TenancyFilterSet): class PrefixFilterSet(NetBoxModelFilterSet, ScopedFilterSet, TenancyFilterSet, ContactModelFilterSet):
family = django_filters.NumberFilter( family = django_filters.NumberFilter(
field_name='prefix', field_name='prefix',
lookup_expr='family' lookup_expr='family'
@ -430,7 +431,7 @@ class PrefixFilterSet(NetBoxModelFilterSet, ScopedFilterSet, TenancyFilterSet):
).distinct() ).distinct()
class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet): class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet, ContactModelFilterSet):
family = django_filters.NumberFilter( family = django_filters.NumberFilter(
field_name='start_address', field_name='start_address',
lookup_expr='family' lookup_expr='family'
@ -522,7 +523,7 @@ class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
return queryset.filter(q) return queryset.filter(q)
class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
family = django_filters.NumberFilter( family = django_filters.NumberFilter(
field_name='address', field_name='address',
lookup_expr='family' lookup_expr='family'
@ -1136,7 +1137,7 @@ class ServiceTemplateFilterSet(NetBoxModelFilterSet):
return queryset.filter(qs_filter) return queryset.filter(qs_filter)
class ServiceFilterSet(NetBoxModelFilterSet): class ServiceFilterSet(ContactModelFilterSet, NetBoxModelFilterSet):
device_id = django_filters.ModelMultipleChoiceFilter( device_id = django_filters.ModelMultipleChoiceFilter(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label=_('Device (ID)'), label=_('Device (ID)'),

View File

@ -6,7 +6,7 @@ from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from ipam.models import * from ipam.models import *
from netbox.forms import NetBoxModelFilterSetForm from netbox.forms import NetBoxModelFilterSetForm
from tenancy.forms import TenancyFilterForm from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, add_blank_choice from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, add_blank_choice
from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
@ -94,12 +94,13 @@ class RIRFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class AggregateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
model = Aggregate model = Aggregate
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
FieldSet('family', 'rir_id', name=_('Attributes')), FieldSet('family', 'rir_id', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
family = forms.ChoiceField( family = forms.ChoiceField(
required=False, required=False,
@ -162,7 +163,7 @@ class RoleFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm, ):
model = Prefix model = Prefix
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
@ -174,6 +175,7 @@ class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')), FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
mask_length__lte = forms.IntegerField( mask_length__lte = forms.IntegerField(
widget=forms.HiddenInput() widget=forms.HiddenInput()
@ -262,12 +264,13 @@ class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
model = IPRange model = IPRange
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_utilized', name=_('Attributes')), FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_utilized', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
family = forms.ChoiceField( family = forms.ChoiceField(
required=False, required=False,
@ -301,7 +304,7 @@ class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
model = IPAddress model = IPAddress
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
@ -312,6 +315,7 @@ class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')), FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('device_id', 'virtual_machine_id', name=_('Device/VM')), FieldSet('device_id', 'virtual_machine_id', name=_('Device/VM')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
selector_fields = ('filter_id', 'q', 'region_id', 'group_id', 'parent', 'status', 'role') selector_fields = ('filter_id', 'q', 'region_id', 'group_id', 'parent', 'status', 'role')
parent = forms.CharField( parent = forms.CharField(
@ -590,12 +594,13 @@ class ServiceTemplateFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class ServiceFilterForm(ServiceTemplateFilterForm): class ServiceFilterForm(ContactModelFilterForm, ServiceTemplateFilterForm):
model = Service model = Service
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
FieldSet('protocol', 'port', name=_('Attributes')), FieldSet('protocol', 'port', name=_('Attributes')),
FieldSet('device_id', 'virtual_machine_id', name=_('Assignment')), FieldSet('device_id', 'virtual_machine_id', name=_('Assignment')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
device_id = DynamicModelMultipleChoiceField( device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),

View File

@ -5,7 +5,7 @@ from django.utils.translation import gettext as _
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 from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet
from tenancy.filtersets import TenancyFilterSet from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
from utilities.filters import ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter from utilities.filters import ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter
from virtualization.models import VirtualMachine, VMInterface from virtualization.models import VirtualMachine, VMInterface
from .choices import * from .choices import *
@ -25,14 +25,14 @@ __all__ = (
) )
class TunnelGroupFilterSet(OrganizationalModelFilterSet): class TunnelGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
class Meta: class Meta:
model = TunnelGroup model = TunnelGroup
fields = ('id', 'name', 'slug', 'description') fields = ('id', 'name', 'slug', 'description')
class TunnelFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class TunnelFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=TunnelStatusChoices choices=TunnelStatusChoices
) )
@ -293,7 +293,7 @@ class IPSecProfileFilterSet(NetBoxModelFilterSet):
) )
class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=L2VPNTypeChoices, choices=L2VPNTypeChoices,
null_value=None null_value=None

View File

@ -5,7 +5,7 @@ from django.utils.translation import gettext as _
from dcim.models import Device, Region, Site from dcim.models import Device, Region, Site
from ipam.models import RouteTarget, VLAN from ipam.models import RouteTarget, VLAN
from netbox.forms import NetBoxModelFilterSetForm from netbox.forms import NetBoxModelFilterSetForm
from tenancy.forms import TenancyFilterForm from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
from utilities.forms.fields import ( from utilities.forms.fields import (
ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField,
) )
@ -30,18 +30,23 @@ __all__ = (
) )
class TunnelGroupFilterForm(NetBoxModelFilterSetForm): class TunnelGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
model = TunnelGroup model = TunnelGroup
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
tag = TagFilterField(model) tag = TagFilterField(model)
class TunnelFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class TunnelFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
model = Tunnel model = Tunnel
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
FieldSet('status', 'encapsulation', 'tunnel_id', name=_('Tunnel')), FieldSet('status', 'encapsulation', 'tunnel_id', name=_('Tunnel')),
FieldSet('ipsec_profile_id', name=_('Security')), FieldSet('ipsec_profile_id', name=_('Security')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenancy')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenancy')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
status = forms.MultipleChoiceField( status = forms.MultipleChoiceField(
label=_('Status'), label=_('Status'),
@ -206,12 +211,13 @@ class IPSecProfileFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class L2VPNFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
model = L2VPN model = L2VPN
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
FieldSet('type', 'import_target_id', 'export_target_id', name=_('Attributes')), FieldSet('type', 'import_target_id', 'export_target_id', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
type = forms.ChoiceField( type = forms.ChoiceField(
label=_('Type'), label=_('Type'),