jeremystretch 4 лет назад
Родитель
Сommit
7c60089692

+ 0 - 36
netbox/extras/filters.py

@@ -1,47 +1,11 @@
 import django_filters
-from django.forms import DateField, IntegerField, NullBooleanField
 
 from .models import Tag
-from .choices import *
 
 __all__ = (
-    'CustomFieldFilter',
     'TagFilter',
 )
 
-EXACT_FILTER_TYPES = (
-    CustomFieldTypeChoices.TYPE_BOOLEAN,
-    CustomFieldTypeChoices.TYPE_DATE,
-    CustomFieldTypeChoices.TYPE_INTEGER,
-    CustomFieldTypeChoices.TYPE_SELECT,
-    CustomFieldTypeChoices.TYPE_MULTISELECT,
-)
-
-
-class CustomFieldFilter(django_filters.Filter):
-    """
-    Filter objects by the presence of a CustomFieldValue. The filter's name is used as the CustomField name.
-    """
-    def __init__(self, custom_field, *args, **kwargs):
-        self.custom_field = custom_field
-
-        if custom_field.type == CustomFieldTypeChoices.TYPE_INTEGER:
-            self.field_class = IntegerField
-        elif custom_field.type == CustomFieldTypeChoices.TYPE_BOOLEAN:
-            self.field_class = NullBooleanField
-        elif custom_field.type == CustomFieldTypeChoices.TYPE_DATE:
-            self.field_class = DateField
-
-        super().__init__(*args, **kwargs)
-
-        self.field_name = f'custom_field_data__{self.field_name}'
-
-        if custom_field.type == CustomFieldTypeChoices.TYPE_MULTISELECT:
-            self.lookup_expr = 'has_key'
-        elif custom_field.type not in EXACT_FILTER_TYPES:
-            if custom_field.filter_logic == CustomFieldFilterLogicChoices.FILTER_LOOSE:
-                self.lookup_expr = 'icontains'
-
 
 class TagFilter(django_filters.ModelMultipleChoiceFilter):
     """

+ 0 - 7
netbox/extras/filtersets.py

@@ -26,13 +26,6 @@ __all__ = (
     'WebhookFilterSet',
 )
 
-EXACT_FILTER_TYPES = (
-    CustomFieldTypeChoices.TYPE_BOOLEAN,
-    CustomFieldTypeChoices.TYPE_DATE,
-    CustomFieldTypeChoices.TYPE_INTEGER,
-    CustomFieldTypeChoices.TYPE_SELECT,
-)
-
 
 class WebhookFilterSet(BaseFilterSet):
     content_types = ContentTypeFilter()

+ 48 - 0
netbox/extras/models/customfields.py

@@ -8,6 +8,7 @@ from django.core.validators import RegexValidator, ValidationError
 from django.db import models
 from django.urls import reverse
 from django.utils.safestring import mark_safe
+from django_filters import filters
 
 from extras.choices import *
 from extras.utils import FeatureQuery, extras_features
@@ -308,6 +309,53 @@ class CustomField(ChangeLoggedModel):
 
         return field
 
+    def to_filter(self):
+        """
+        Return a django_filters Filter instance suitable for this field type.
+        """
+        kwargs = {
+            'field_name': f'custom_field_data__{self.name}'
+        }
+
+        # Text/URL
+        if self.type in (
+                CustomFieldTypeChoices.TYPE_TEXT,
+                CustomFieldTypeChoices.TYPE_LONGTEXT,
+                CustomFieldTypeChoices.TYPE_URL,
+        ):
+            filter_class = filters.CharFilter
+            if self.filter_logic == CustomFieldFilterLogicChoices.FILTER_LOOSE:
+                kwargs['lookup_expr'] = 'icontains'
+
+        # Integer
+        elif self.type == CustomFieldTypeChoices.TYPE_INTEGER:
+            # TODO: Remove dirty hack to change lookup type from Decimal
+            filter_class = filters.NumberFilter
+            filter_class.field_class = forms.IntegerField
+
+        # Boolean
+        elif self.type == CustomFieldTypeChoices.TYPE_BOOLEAN:
+            filter_class = filters.BooleanFilter
+
+        # Date
+        elif self.type == CustomFieldTypeChoices.TYPE_DATE:
+            filter_class = filters.DateFilter
+
+        # Select
+        elif self.type == CustomFieldTypeChoices.TYPE_SELECT:
+            filter_class = filters.CharFilter
+
+        # Multiselect
+        elif self.type == CustomFieldTypeChoices.TYPE_MULTISELECT:
+            filter_class = filters.CharFilter
+            kwargs['lookup_expr'] = 'has_key'
+
+        # Unsupported custom field type
+        else:
+            return None
+
+        return filter_class(**kwargs)
+
     def validate(self, value):
         """
         Validate a value according to the field's type validation rules.

+ 5 - 4
netbox/netbox/filtersets.py

@@ -7,7 +7,7 @@ from django_filters.utils import get_model_field, resolve_field
 
 from dcim.forms import MACAddressField
 from extras.choices import CustomFieldFilterLogicChoices
-from extras.filters import CustomFieldFilter, TagFilter
+from extras.filters import TagFilter
 from extras.models import CustomField
 from utilities.constants import (
     FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP,
@@ -15,7 +15,6 @@ from utilities.constants import (
 )
 from utilities import filters
 
-
 __all__ = (
     'BaseFilterSet',
     'ChangeLoggedModelFilterSet',
@@ -222,8 +221,10 @@ class PrimaryModelFilterSet(ChangeLoggedModelFilterSet):
         )
 
         custom_field_filters = {}
-        for cf in custom_fields:
-            custom_field_filters[f'cf_{cf.name}'] = CustomFieldFilter(field_name=cf.name, custom_field=cf)
+        for custom_field in custom_fields:
+            cf_filter = custom_field.to_filter()
+            if cf_filter:
+                custom_field_filters[f'cf_{custom_field.name}'] = cf_filter
 
         self.filters.update(custom_field_filters)