mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Update query filters to OR multiple values
This commit is contained in:
@ -9,7 +9,7 @@ from .constants import CIRCUIT_STATUS_CHOICES
|
|||||||
from .models import Provider, Circuit, CircuitTermination, CircuitType
|
from .models import Provider, Circuit, CircuitTermination, CircuitType
|
||||||
|
|
||||||
|
|
||||||
class ProviderFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class ProviderFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -54,7 +54,7 @@ class CircuitTypeFilter(NameSlugSearchFilterSet):
|
|||||||
fields = ['name', 'slug']
|
fields = ['name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class CircuitFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class CircuitFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
|
@ -13,7 +13,7 @@ from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_
|
|||||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||||
|
|
||||||
|
|
||||||
class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class VRFFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -59,7 +59,7 @@ class RIRFilter(NameSlugSearchFilterSet):
|
|||||||
fields = ['name', 'slug', 'is_private']
|
fields = ['name', 'slug', 'is_private']
|
||||||
|
|
||||||
|
|
||||||
class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class AggregateFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -107,7 +107,7 @@ class RoleFilter(NameSlugSearchFilterSet):
|
|||||||
fields = ['name', 'slug']
|
fields = ['name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class PrefixFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -254,7 +254,7 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
return queryset.filter(prefix__net_mask_length=value)
|
return queryset.filter(prefix__net_mask_length=value)
|
||||||
|
|
||||||
|
|
||||||
class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class IPAddressFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
@ -395,7 +395,7 @@ class VLANGroupFilter(NameSlugSearchFilterSet):
|
|||||||
fields = ['name', 'slug']
|
fields = ['name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class VLANFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
|
@ -14,7 +14,7 @@ class SecretRoleFilter(NameSlugSearchFilterSet):
|
|||||||
fields = ['name', 'slug']
|
fields = ['name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class SecretFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class SecretFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
|
@ -13,7 +13,7 @@ class TenantGroupFilter(NameSlugSearchFilterSet):
|
|||||||
fields = ['name', 'slug']
|
fields = ['name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class TenantFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
class TenantFilter(CustomFieldFilterSet):
|
||||||
id__in = NumericInFilter(
|
id__in = NumericInFilter(
|
||||||
field_name='id',
|
field_name='id',
|
||||||
lookup_expr='in'
|
lookup_expr='in'
|
||||||
|
@ -1,10 +1,51 @@
|
|||||||
import django_filters
|
import django_filters
|
||||||
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import Q
|
from django.db import models
|
||||||
|
|
||||||
from extras.models import Tag
|
from extras.models import Tag
|
||||||
|
|
||||||
|
|
||||||
|
def multivalue_field_factory(field_class):
|
||||||
|
"""
|
||||||
|
Given a form field class, return a subclass capable of accepting multiple values. This allows us to OR on multiple
|
||||||
|
filter values while maintaining the field's built-in vlaidation. Example: GET /api/dcim/devices/?name=foo&name=bar
|
||||||
|
"""
|
||||||
|
class NewField(field_class):
|
||||||
|
widget = forms.SelectMultiple
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
if not value:
|
||||||
|
return []
|
||||||
|
return [super(field_class, self).to_python(v) for v in value]
|
||||||
|
|
||||||
|
return type('MultiValue{}'.format(field_class.__name__), (NewField,), dict())
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Filters
|
||||||
|
#
|
||||||
|
|
||||||
|
class MultiValueCharFilter(django_filters.MultipleChoiceFilter):
|
||||||
|
field_class = multivalue_field_factory(forms.CharField)
|
||||||
|
|
||||||
|
|
||||||
|
class MultiValueDateFilter(django_filters.MultipleChoiceFilter):
|
||||||
|
field_class = multivalue_field_factory(forms.DateField)
|
||||||
|
|
||||||
|
|
||||||
|
class MultiValueDateTimeFilter(django_filters.MultipleChoiceFilter):
|
||||||
|
field_class = multivalue_field_factory(forms.DateTimeField)
|
||||||
|
|
||||||
|
|
||||||
|
class MultiValueNumberFilter(django_filters.MultipleChoiceFilter):
|
||||||
|
field_class = multivalue_field_factory(forms.IntegerField)
|
||||||
|
|
||||||
|
|
||||||
|
class MultiValueTimeFilter(django_filters.MultipleChoiceFilter):
|
||||||
|
field_class = multivalue_field_factory(forms.TimeField)
|
||||||
|
|
||||||
|
|
||||||
class TreeNodeMultipleChoiceFilter(django_filters.ModelMultipleChoiceFilter):
|
class TreeNodeMultipleChoiceFilter(django_filters.ModelMultipleChoiceFilter):
|
||||||
"""
|
"""
|
||||||
Filters for a set of Models, including all descendant models within a Tree. Example: [<Region: R1>,<Region: R2>]
|
Filters for a set of Models, including all descendant models within a Tree. Example: [<Region: R1>,<Region: R2>]
|
||||||
@ -48,6 +89,10 @@ class TagFilter(django_filters.ModelMultipleChoiceFilter):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# FilterSets
|
||||||
|
#
|
||||||
|
|
||||||
class NameSlugSearchFilterSet(django_filters.FilterSet):
|
class NameSlugSearchFilterSet(django_filters.FilterSet):
|
||||||
"""
|
"""
|
||||||
A base class for adding the search method to models which only expose the `name` and `slug` fields
|
A base class for adding the search method to models which only expose the `name` and `slug` fields
|
||||||
@ -61,6 +106,57 @@ class NameSlugSearchFilterSet(django_filters.FilterSet):
|
|||||||
if not value.strip():
|
if not value.strip():
|
||||||
return queryset
|
return queryset
|
||||||
return queryset.filter(
|
return queryset.filter(
|
||||||
Q(name__icontains=value) |
|
models.Q(name__icontains=value) |
|
||||||
Q(slug__icontains=value)
|
models.Q(slug__icontains=value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Update default filters
|
||||||
|
#
|
||||||
|
|
||||||
|
FILTER_DEFAULTS = django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS
|
||||||
|
FILTER_DEFAULTS.update({
|
||||||
|
models.AutoField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.CharField: {
|
||||||
|
'filter_class': MultiValueCharFilter
|
||||||
|
},
|
||||||
|
models.DateField: {
|
||||||
|
'filter_class': MultiValueDateFilter
|
||||||
|
},
|
||||||
|
models.DateTimeField: {
|
||||||
|
'filter_class': MultiValueDateTimeFilter
|
||||||
|
},
|
||||||
|
models.DecimalField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.EmailField: {
|
||||||
|
'filter_class': MultiValueCharFilter
|
||||||
|
},
|
||||||
|
models.FloatField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.IntegerField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.PositiveIntegerField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.PositiveSmallIntegerField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.SlugField: {
|
||||||
|
'filter_class': MultiValueCharFilter
|
||||||
|
},
|
||||||
|
models.SmallIntegerField: {
|
||||||
|
'filter_class': MultiValueNumberFilter
|
||||||
|
},
|
||||||
|
models.TimeField: {
|
||||||
|
'filter_class': MultiValueTimeFilter
|
||||||
|
},
|
||||||
|
models.URLField: {
|
||||||
|
'filter_class': MultiValueCharFilter
|
||||||
|
},
|
||||||
|
})
|
||||||
|
Reference in New Issue
Block a user