1
0
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:
Jeremy Stretch
2019-05-07 12:25:33 -04:00
parent a8c57313d3
commit 6cb5173e27
5 changed files with 108 additions and 12 deletions

View File

@ -1,10 +1,51 @@
import django_filters
from django import forms
from django.conf import settings
from django.db.models import Q
from django.db import models
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):
"""
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)
#
# FilterSets
#
class NameSlugSearchFilterSet(django_filters.FilterSet):
"""
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():
return queryset
return queryset.filter(
Q(name__icontains=value) |
Q(slug__icontains=value)
models.Q(name__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
},
})