diff --git a/netbox/templates/inc/messages.html b/netbox/templates/inc/messages.html
index 1cb9a6215..b5d03135f 100644
--- a/netbox/templates/inc/messages.html
+++ b/netbox/templates/inc/messages.html
@@ -1,27 +1,6 @@
{% load helpers %}
- {# Django Messages #}
-
- {# Form Field Errors #}
- {% if form and form.errors %}
- {% for field in form %}
- {% for error in field.errors %}
-
-
-
- {{ error|escape }}
-
-
- {% endfor %}
- {% endfor %}
- {% endif %}
{# Non-Field Form Errors #}
{% if form and form.non_field_errors %}
diff --git a/netbox/utilities/forms/forms.py b/netbox/utilities/forms/forms.py
index 5756cf0e3..af06f219a 100644
--- a/netbox/utilities/forms/forms.py
+++ b/netbox/utilities/forms/forms.py
@@ -48,10 +48,16 @@ class BootstrapMixin:
]
for field_name, field in self.fields.items():
+ css = field.widget.attrs.get('class', '')
if field.widget.__class__ not in exempt_widgets:
- css = field.widget.attrs.get('class', '')
- field.widget.attrs['class'] = ' '.join([css, 'form-control']).strip()
+ field.widget.attrs['class'] = f'{css} form-control'
+
+ elif isinstance(field.widget, forms.CheckboxInput):
+ field.widget.attrs['class'] = f'{css} form-check-input'
+
+ elif isinstance(field.widget, forms.Select):
+ field.widget.attrs['class'] = f'{css} form-select'
if field.required and not isinstance(field.widget, forms.FileInput):
field.widget.attrs['required'] = 'required'
@@ -59,13 +65,18 @@ class BootstrapMixin:
if 'placeholder' not in field.widget.attrs and field.label is not None:
field.widget.attrs['placeholder'] = field.label
- if field.widget.__class__ == forms.CheckboxInput:
- css = field.widget.attrs.get('class', '')
- field.widget.attrs['class'] = ' '.join((css, 'form-check-input')).strip()
+ def is_valid(self):
+ is_valid = super().is_valid()
- if field.widget.__class__ == forms.Select:
- css = field.widget.attrs.get('class', '')
- field.widget.attrs['class'] = ' '.join((css, 'form-select')).strip()
+ # Apply is-invalid CSS class to fields with errors
+ if not is_valid:
+ for field_name in self.errors:
+ # Ignore e.g. __all__
+ if field := self.fields.get(field_name):
+ css = field.widget.attrs.get('class', '')
+ field.widget.attrs['class'] = f'{css} is-invalid'
+
+ return is_valid
#
diff --git a/netbox/utilities/templates/form_helpers/render_field.html b/netbox/utilities/templates/form_helpers/render_field.html
index 4c6c46ef0..ec9ceb09a 100644
--- a/netbox/utilities/templates/form_helpers/render_field.html
+++ b/netbox/utilities/templates/form_helpers/render_field.html
@@ -1,127 +1,65 @@
{% load form_helpers %}
{% load helpers %}
-{% if field|widget_type == 'checkboxinput' %}
-
-
-
-
- {{ field }}
-
-
- {% if field.help_text %}
-
{{ field.help_text|safe }}
- {% endif %}
- {% if bulk_nullable %}
-
-
-
-
- {% endif %}
-
-
+
-{% elif field|widget_type == 'textarea' and not label %}
-
- {% if label %}
-