Bläddra i källkod

Fixes #8358: Fix inconsistent styling of custom fields on filter & bulk edit forms

jeremystretch 4 år sedan
förälder
incheckning
2b31154834

+ 1 - 0
docs/release-notes/version-3.1.md

@@ -24,6 +24,7 @@
 * [#8319](https://github.com/netbox-community/netbox/issues/8319) - Custom URL fields should honor `ALLOWED_URL_SCHEMES` config parameter
 * [#8342](https://github.com/netbox-community/netbox/issues/8342) - Restore `created` & `last_updated` fields missing from several REST API serializers
 * [#8357](https://github.com/netbox-community/netbox/issues/8357) - Add missing tags field to location filter form
+* [#8358](https://github.com/netbox-community/netbox/issues/8358) - Fix inconsistent styling of custom fields on filter & bulk edit forms
 
 ---
 

+ 28 - 31
netbox/extras/forms/customfields.py

@@ -4,7 +4,7 @@ from django.db.models import Q
 
 from extras.choices import *
 from extras.models import *
-from utilities.forms import BootstrapMixin, BulkEditForm, CSVModelForm, FilterForm
+from utilities.forms import BootstrapMixin, BulkEditBaseForm, CSVModelForm
 
 __all__ = (
     'CustomFieldModelCSVForm',
@@ -34,6 +34,9 @@ class CustomFieldsMixin:
             raise NotImplementedError(f"{self.__class__.__name__} must specify a model class.")
         return ContentType.objects.get_for_model(self.model)
 
+    def _get_custom_fields(self, content_type):
+        return CustomField.objects.filter(content_types=content_type)
+
     def _get_form_field(self, customfield):
         return customfield.to_form_field()
 
@@ -41,10 +44,7 @@ class CustomFieldsMixin:
         """
         Append form fields for all CustomFields assigned to this object type.
         """
-        content_type = self._get_content_type()
-
-        # Append form fields; assign initial values if modifying and existing object
-        for customfield in CustomField.objects.filter(content_types=content_type):
+        for customfield in self._get_custom_fields(self._get_content_type()):
             field_name = f'cf_{customfield.name}'
             self.fields[field_name] = self._get_form_field(customfield)
 
@@ -86,40 +86,37 @@ class CustomFieldModelCSVForm(CSVModelForm, CustomFieldModelForm):
         return customfield.to_form_field(for_csv_import=True)
 
 
-class CustomFieldModelBulkEditForm(BulkEditForm):
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
+class CustomFieldModelBulkEditForm(BootstrapMixin, CustomFieldsMixin, BulkEditBaseForm):
 
-        self.custom_fields = []
-        self.obj_type = ContentType.objects.get_for_model(self.model)
+    def _get_form_field(self, customfield):
+        return customfield.to_form_field(set_initial=False, enforce_required=False)
 
-        # Add all applicable CustomFields to the form
-        custom_fields = CustomField.objects.filter(content_types=self.obj_type)
-        for cf in custom_fields:
+    def _append_customfield_fields(self):
+        """
+        Append form fields for all CustomFields assigned to this object type.
+        """
+        for customfield in self._get_custom_fields(self._get_content_type()):
             # Annotate non-required custom fields as nullable
-            if not cf.required:
-                self.nullable_fields.append(cf.name)
-            self.fields[cf.name] = cf.to_form_field(set_initial=False, enforce_required=False)
-            # Annotate this as a custom field
-            self.custom_fields.append(cf.name)
+            if not customfield.required:
+                self.nullable_fields.append(customfield.name)
 
+            self.fields[customfield.name] = self._get_form_field(customfield)
 
-class CustomFieldModelFilterForm(FilterForm):
-
-    def __init__(self, *args, **kwargs):
+            # Annotate the field in the list of CustomField form fields
+            self.custom_fields.append(customfield.name)
 
-        self.obj_type = ContentType.objects.get_for_model(self.model)
 
-        super().__init__(*args, **kwargs)
+class CustomFieldModelFilterForm(BootstrapMixin, CustomFieldsMixin, forms.Form):
+    q = forms.CharField(
+        required=False,
+        label='Search'
+    )
 
-        # Add all applicable CustomFields to the form
-        self.custom_field_filters = []
-        custom_fields = CustomField.objects.filter(content_types=self.obj_type).exclude(
+    def _get_custom_fields(self, content_type):
+        return CustomField.objects.filter(content_types=content_type).exclude(
             Q(filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED) |
             Q(type=CustomFieldTypeChoices.TYPE_JSON)
         )
-        for cf in custom_fields:
-            field_name = f'cf_{cf.name}'
-            self.fields[field_name] = cf.to_form_field(set_initial=False, enforce_required=False)
-            self.custom_field_filters.append(field_name)
+
+    def _get_form_field(self, customfield):
+        return customfield.to_form_field(set_initial=False, enforce_required=False)

+ 3 - 3
netbox/templates/inc/filter_list.html

@@ -24,17 +24,17 @@
       {% else %}
         {# List all non-customfield filters as declared in the form class #}
         {% for field in filter_form.visible_fields %}
-          {% if not filter_form.custom_field_filters or field.name not in filter_form.custom_field_filters %}
+          {% if not filter_form.custom_fields or field.name not in filter_form.custom_fields %}
             <div class="col col-12">
               {% render_field field %}
             </div>
           {% endif %}
         {% endfor %}
       {% endif %}
-      {% if filter_form.custom_field_filters %}
+      {% if filter_form.custom_fields %}
         {# List all custom field filters #}
         <hr class="card-divider mt-0" />
-        {% for name in filter_form.custom_field_filters %}
+        {% for name in filter_form.custom_fields %}
           <div class="col col-12">
             {% with field=filter_form|get_item:name %}
               {% render_field field %}

+ 7 - 7
netbox/utilities/forms/forms.py

@@ -3,7 +3,6 @@ import re
 
 import yaml
 from django import forms
-from django.utils.translation import gettext as _
 
 from .widgets import APISelect, APISelectMultiple, ClearableFileInput, StaticSelect
 
@@ -11,6 +10,7 @@ from .widgets import APISelect, APISelectMultiple, ClearableFileInput, StaticSel
 __all__ = (
     'BootstrapMixin',
     'BulkEditForm',
+    'BulkEditBaseForm',
     'BulkRenameForm',
     'ConfirmationForm',
     'CSVModelForm',
@@ -75,11 +75,10 @@ class ConfirmationForm(BootstrapMixin, ReturnURLForm):
     confirm = forms.BooleanField(required=True, widget=forms.HiddenInput(), initial=True)
 
 
-class BulkEditForm(BootstrapMixin, forms.Form):
+class BulkEditBaseForm(forms.Form):
     """
     Base form for editing multiple objects in bulk
     """
-
     def __init__(self, model, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.model = model
@@ -90,6 +89,10 @@ class BulkEditForm(BootstrapMixin, forms.Form):
             self.nullable_fields = self.Meta.nullable_fields
 
 
+class BulkEditForm(BootstrapMixin, BulkEditBaseForm):
+    pass
+
+
 class BulkRenameForm(BootstrapMixin, forms.Form):
     """
     An extendable form to be used for renaming objects in bulk.
@@ -185,10 +188,7 @@ class FilterForm(BootstrapMixin, forms.Form):
     """
     q = forms.CharField(
         required=False,
-        widget=forms.TextInput(
-            attrs={'placeholder': _('All fields')}
-        ),
-        label=_('Search')
+        label='Search'
     )