mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Closes #5451: Add support for multiple-selection custom fields
This commit is contained in:
@@ -13,6 +13,7 @@ class CustomFieldTypeChoices(ChoiceSet):
|
||||
TYPE_DATE = 'date'
|
||||
TYPE_URL = 'url'
|
||||
TYPE_SELECT = 'select'
|
||||
TYPE_MULTISELECT = 'multiselect'
|
||||
|
||||
CHOICES = (
|
||||
(TYPE_TEXT, 'Text'),
|
||||
@@ -21,6 +22,7 @@ class CustomFieldTypeChoices(ChoiceSet):
|
||||
(TYPE_DATE, 'Date'),
|
||||
(TYPE_URL, 'URL'),
|
||||
(TYPE_SELECT, 'Selection'),
|
||||
(TYPE_MULTISELECT, 'Multiple selection'),
|
||||
)
|
||||
|
||||
|
||||
|
@@ -11,7 +11,9 @@ from django.utils.safestring import mark_safe
|
||||
from extras.choices import *
|
||||
from extras.utils import FeatureQuery
|
||||
from netbox.models import BigIDModel
|
||||
from utilities.forms import CSVChoiceField, DatePicker, LaxURLField, StaticSelect2, add_blank_choice
|
||||
from utilities.forms import (
|
||||
CSVChoiceField, DatePicker, LaxURLField, StaticSelect2Multiple, StaticSelect2, add_blank_choice,
|
||||
)
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
from utilities.validators import validate_regex
|
||||
|
||||
@@ -153,7 +155,10 @@ class CustomField(BigIDModel):
|
||||
})
|
||||
|
||||
# Choices can be set only on selection fields
|
||||
if self.choices and self.type != CustomFieldTypeChoices.TYPE_SELECT:
|
||||
if self.choices and self.type not in (
|
||||
CustomFieldTypeChoices.TYPE_SELECT,
|
||||
CustomFieldTypeChoices.TYPE_MULTISELECT
|
||||
):
|
||||
raise ValidationError({
|
||||
'choices': "Choices may be set only for custom selection fields."
|
||||
})
|
||||
@@ -206,7 +211,7 @@ class CustomField(BigIDModel):
|
||||
field = forms.DateField(required=required, initial=initial, widget=DatePicker())
|
||||
|
||||
# Select
|
||||
elif self.type == CustomFieldTypeChoices.TYPE_SELECT:
|
||||
elif self.type in (CustomFieldTypeChoices.TYPE_SELECT, CustomFieldTypeChoices.TYPE_MULTISELECT):
|
||||
choices = [(c, c) for c in self.choices]
|
||||
default_choice = self.default if self.default in self.choices else None
|
||||
|
||||
@@ -217,10 +222,16 @@ class CustomField(BigIDModel):
|
||||
if set_initial and default_choice:
|
||||
initial = default_choice
|
||||
|
||||
field_class = CSVChoiceField if for_csv_import else forms.ChoiceField
|
||||
field = field_class(
|
||||
choices=choices, required=required, initial=initial, widget=StaticSelect2()
|
||||
)
|
||||
if self.type == CustomFieldTypeChoices.TYPE_SELECT:
|
||||
field_class = CSVChoiceField if for_csv_import else forms.ChoiceField
|
||||
field = field_class(
|
||||
choices=choices, required=required, initial=initial, widget=StaticSelect2()
|
||||
)
|
||||
else:
|
||||
field_class = CSVChoiceField if for_csv_import else forms.MultipleChoiceField
|
||||
field = field_class(
|
||||
choices=choices, required=required, initial=initial, widget=StaticSelect2Multiple()
|
||||
)
|
||||
|
||||
# URL
|
||||
elif self.type == CustomFieldTypeChoices.TYPE_URL:
|
||||
@@ -285,5 +296,12 @@ class CustomField(BigIDModel):
|
||||
f"Invalid choice ({value}). Available choices are: {', '.join(self.choices)}"
|
||||
)
|
||||
|
||||
# Validate all selected choices
|
||||
if self.type == CustomFieldTypeChoices.TYPE_MULTISELECT:
|
||||
if not set(value).issubset(self.choices):
|
||||
raise ValidationError(
|
||||
f"Invalid choice(s) ({', '.join(value)}). Available choices are: {', '.join(self.choices)}"
|
||||
)
|
||||
|
||||
elif self.required:
|
||||
raise ValidationError("Required field cannot be empty.")
|
||||
|
@@ -15,6 +15,8 @@
|
||||
<i class="mdi mdi-close-thick text-danger" title="False"></i>
|
||||
{% elif field.type == 'url' and value %}
|
||||
<a href="{{ value }}">{{ value|truncatechars:70 }}</a>
|
||||
{% elif field.type == 'multiselect' and value %}
|
||||
{{ value|join:", " }}
|
||||
{% elif value is not None %}
|
||||
{{ value }}
|
||||
{% elif field.required %}
|
||||
|
Reference in New Issue
Block a user