mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 01:41:22 -06:00
Fixes #2558: Filter on all tags when multiple are passed
This commit is contained in:
parent
b6a256dc5d
commit
0c33af2140
@ -3,6 +3,7 @@ v2.4.8 (FUTURE)
|
|||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
|
|
||||||
* [#2473](https://github.com/digitalocean/netbox/issues/2473) - Fix encoding of long (>127 character) secrets
|
* [#2473](https://github.com/digitalocean/netbox/issues/2473) - Fix encoding of long (>127 character) secrets
|
||||||
|
* [#2558](https://github.com/digitalocean/netbox/issues/2558) - Filter on all tags when multiple are passed
|
||||||
* [#2575](https://github.com/digitalocean/netbox/issues/2575) - Correct model specified for rack roles table
|
* [#2575](https://github.com/digitalocean/netbox/issues/2575) - Correct model specified for rack roles table
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -6,7 +6,7 @@ from django.db.models import Q
|
|||||||
from dcim.models import Site
|
from dcim.models import Site
|
||||||
from extras.filters import CustomFieldFilterSet
|
from extras.filters import CustomFieldFilterSet
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.filters import NumericInFilter
|
from utilities.filters import NumericInFilter, TagFilter
|
||||||
from .constants import CIRCUIT_STATUS_CHOICES
|
from .constants import CIRCUIT_STATUS_CHOICES
|
||||||
from .models import Provider, Circuit, CircuitTermination, CircuitType
|
from .models import Provider, Circuit, CircuitTermination, CircuitType
|
||||||
|
|
||||||
@ -28,9 +28,7 @@ class ProviderFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Site (slug)',
|
label='Site (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Provider
|
model = Provider
|
||||||
@ -106,9 +104,7 @@ class CircuitFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Site (slug)',
|
label='Site (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Circuit
|
model = Circuit
|
||||||
|
@ -9,7 +9,7 @@ from netaddr.core import AddrFormatError
|
|||||||
|
|
||||||
from extras.filters import CustomFieldFilterSet
|
from extras.filters import CustomFieldFilterSet
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.filters import NullableCharFieldFilter, NumericInFilter
|
from utilities.filters import NullableCharFieldFilter, NumericInFilter, TagFilter
|
||||||
from virtualization.models import Cluster
|
from virtualization.models import Cluster
|
||||||
from .constants import (
|
from .constants import (
|
||||||
DEVICE_STATUS_CHOICES, IFACE_FF_LAG, NONCONNECTABLE_IFACE_TYPES, SITE_STATUS_CHOICES, VIRTUAL_IFACE_TYPES,
|
DEVICE_STATUS_CHOICES, IFACE_FF_LAG, NONCONNECTABLE_IFACE_TYPES, SITE_STATUS_CHOICES, VIRTUAL_IFACE_TYPES,
|
||||||
@ -83,9 +83,7 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Tenant (slug)',
|
label='Tenant (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Site
|
model = Site
|
||||||
@ -196,9 +194,7 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Role (slug)',
|
label='Role (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rack
|
model = Rack
|
||||||
@ -306,9 +302,7 @@ class DeviceTypeFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Manufacturer (slug)',
|
label='Manufacturer (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
@ -530,9 +524,7 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
queryset=VirtualChassis.objects.all(),
|
queryset=VirtualChassis.objects.all(),
|
||||||
label='Virtual chassis (ID)',
|
label='Virtual chassis (ID)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Device
|
model = Device
|
||||||
@ -592,9 +584,7 @@ class DeviceComponentFilterSet(django_filters.FilterSet):
|
|||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
label='Device (name)',
|
label='Device (name)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ConsolePortFilter(DeviceComponentFilterSet):
|
class ConsolePortFilter(DeviceComponentFilterSet):
|
||||||
@ -653,9 +643,7 @@ class InterfaceFilter(django_filters.FilterSet):
|
|||||||
method='_mac_address',
|
method='_mac_address',
|
||||||
label='MAC address',
|
label='MAC address',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
vlan_id = django_filters.CharFilter(
|
vlan_id = django_filters.CharFilter(
|
||||||
method='filter_vlan_id',
|
method='filter_vlan_id',
|
||||||
label='Assigned VLAN'
|
label='Assigned VLAN'
|
||||||
@ -797,9 +785,7 @@ class VirtualChassisFilter(django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Tenant (slug)',
|
label='Tenant (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
|
@ -9,7 +9,7 @@ from netaddr.core import AddrFormatError
|
|||||||
from dcim.models import Site, Device, Interface
|
from dcim.models import Site, Device, Interface
|
||||||
from extras.filters import CustomFieldFilterSet
|
from extras.filters import CustomFieldFilterSet
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.filters import NumericInFilter
|
from utilities.filters import NumericInFilter, TagFilter
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_STATUS_CHOICES, VLAN_STATUS_CHOICES
|
from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_STATUS_CHOICES, VLAN_STATUS_CHOICES
|
||||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||||
@ -31,9 +31,7 @@ class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Tenant (slug)',
|
label='Tenant (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -73,9 +71,7 @@ class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='RIR (slug)',
|
label='RIR (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Aggregate
|
model = Aggregate
|
||||||
@ -174,9 +170,7 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
choices=PREFIX_STATUS_CHOICES,
|
choices=PREFIX_STATUS_CHOICES,
|
||||||
null_value=None
|
null_value=None
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Prefix
|
model = Prefix
|
||||||
@ -303,9 +297,7 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
role = django_filters.MultipleChoiceFilter(
|
role = django_filters.MultipleChoiceFilter(
|
||||||
choices=IPADDRESS_ROLE_CHOICES
|
choices=IPADDRESS_ROLE_CHOICES
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
@ -422,9 +414,7 @@ class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
choices=VLAN_STATUS_CHOICES,
|
choices=VLAN_STATUS_CHOICES,
|
||||||
null_value=None
|
null_value=None
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VLAN
|
model = VLAN
|
||||||
@ -466,9 +456,7 @@ class ServiceFilter(django_filters.FilterSet):
|
|||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
label='Virtual machine (name)',
|
label='Virtual machine (name)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Service
|
model = Service
|
||||||
|
@ -5,7 +5,7 @@ from django.db.models import Q
|
|||||||
|
|
||||||
from dcim.models import Device
|
from dcim.models import Device
|
||||||
from extras.filters import CustomFieldFilterSet
|
from extras.filters import CustomFieldFilterSet
|
||||||
from utilities.filters import NumericInFilter
|
from utilities.filters import NumericInFilter, TagFilter
|
||||||
from .models import Secret, SecretRole
|
from .models import Secret, SecretRole
|
||||||
|
|
||||||
|
|
||||||
@ -42,9 +42,7 @@ class SecretFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
label='Device (name)',
|
label='Device (name)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Secret
|
model = Secret
|
||||||
|
@ -4,7 +4,7 @@ import django_filters
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
|
||||||
from extras.filters import CustomFieldFilterSet
|
from extras.filters import CustomFieldFilterSet
|
||||||
from utilities.filters import NumericInFilter
|
from utilities.filters import NumericInFilter, TagFilter
|
||||||
from .models import Tenant, TenantGroup
|
from .models import Tenant, TenantGroup
|
||||||
|
|
||||||
|
|
||||||
@ -31,9 +31,7 @@ class TenantFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Group (slug)',
|
label='Group (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Tenant
|
model = Tenant
|
||||||
|
@ -5,6 +5,7 @@ import itertools
|
|||||||
import django_filters
|
import django_filters
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
from taggit.models import Tag
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -68,3 +69,18 @@ class NullableModelMultipleChoiceField(forms.ModelMultipleChoiceField):
|
|||||||
stripped_value = value
|
stripped_value = value
|
||||||
super(NullableModelMultipleChoiceField, self).clean(stripped_value)
|
super(NullableModelMultipleChoiceField, self).clean(stripped_value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class TagFilter(django_filters.ModelMultipleChoiceFilter):
|
||||||
|
"""
|
||||||
|
Match on one or more assigned tags. If multiple tags are specified (e.g. ?tag=foo&tag=bar), the queryset is filtered
|
||||||
|
to objects matching all tags.
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
kwargs.setdefault('name', 'tags__slug')
|
||||||
|
kwargs.setdefault('to_field_name', 'slug')
|
||||||
|
kwargs.setdefault('conjoined', True)
|
||||||
|
kwargs.setdefault('queryset', Tag.objects.all())
|
||||||
|
|
||||||
|
super(TagFilter, self).__init__(*args, **kwargs)
|
||||||
|
@ -9,7 +9,7 @@ from netaddr.core import AddrFormatError
|
|||||||
from dcim.models import DeviceRole, Interface, Platform, Region, Site
|
from dcim.models import DeviceRole, Interface, Platform, Region, Site
|
||||||
from extras.filters import CustomFieldFilterSet
|
from extras.filters import CustomFieldFilterSet
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.filters import NumericInFilter
|
from utilities.filters import NumericInFilter, TagFilter
|
||||||
from .constants import VM_STATUS_CHOICES
|
from .constants import VM_STATUS_CHOICES
|
||||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||||
|
|
||||||
@ -64,9 +64,7 @@ class ClusterFilter(CustomFieldFilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Site (slug)',
|
label='Site (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
@ -168,9 +166,7 @@ class VirtualMachineFilter(CustomFieldFilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Platform (slug)',
|
label='Platform (slug)',
|
||||||
)
|
)
|
||||||
tag = django_filters.CharFilter(
|
tag = TagFilter()
|
||||||
name='tags__slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
|
Loading…
Reference in New Issue
Block a user