diff --git a/netbox/extras/forms.py b/netbox/extras/forms.py index 674c3ff4c..f5d331ac4 100644 --- a/netbox/extras/forms.py +++ b/netbox/extras/forms.py @@ -20,22 +20,6 @@ from .models import ConfigContext, CustomField, CustomFieldValue, ImageAttachmen # Custom fields # -def get_custom_fields_for_model(content_type, filterable_only=False, bulk_edit=False): - """ - Retrieve all CustomFields applicable to the given ContentType - """ - field_dict = OrderedDict() - custom_fields = CustomField.objects.filter(obj_type=content_type) - if filterable_only: - custom_fields = custom_fields.exclude(filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED) - - for cf in custom_fields: - field_name = 'cf_{}'.format(str(cf.name)) - field_dict[field_name] = cf.to_form_field(set_initial=not bulk_edit) - - return field_dict - - class CustomFieldModelForm(forms.ModelForm): def __init__(self, *args, **kwargs): @@ -60,9 +44,10 @@ class CustomFieldModelForm(forms.ModelForm): Append form fields for all applicable CustomFields. """ self.custom_fields = [] - for name, field in get_custom_fields_for_model(self.obj_type).items(): - self.fields[name] = field - self.custom_fields.append(name) + custom_fields = CustomField.objects.filter(obj_type=self.obj_type) + for cf in custom_fields: + self.fields[cf.name] = cf.to_form_field() + self.custom_fields.append(cf.name) def _save_custom_fields(self): @@ -106,15 +91,14 @@ class CustomFieldBulkEditForm(BulkEditForm): self.obj_type = ContentType.objects.get_for_model(self.model) # Add all applicable CustomFields to the form - custom_fields = get_custom_fields_for_model(self.obj_type, bulk_edit=True).items() - for name, field in custom_fields: + custom_fields = CustomField.objects.filter(obj_type=self.obj_type) + for cf in custom_fields: # Annotate non-required custom fields as nullable - if not field.required: - self.nullable_fields.append(name) - field.required = False - self.fields[name] = field + 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(name) + self.custom_fields.append(cf.name) class CustomFieldFilterForm(forms.Form): @@ -126,10 +110,11 @@ class CustomFieldFilterForm(forms.Form): super().__init__(*args, **kwargs) # Add all applicable CustomFields to the form - custom_fields = get_custom_fields_for_model(self.obj_type, filterable_only=True).items() - for name, field in custom_fields: - field.required = False - self.fields[name] = field + custom_fields = CustomField.objects.filter(obj_type=self.obj_type).exclude( + filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED + ) + for cf in custom_fields: + self.fields[cf.name] = cf.to_form_field(set_initial=True, enforce_required=False) # diff --git a/netbox/extras/models.py b/netbox/extras/models.py index be8feda7b..db42fc845 100644 --- a/netbox/extras/models.py +++ b/netbox/extras/models.py @@ -282,17 +282,19 @@ class CustomField(models.Model): return self.choices.get(pk=int(serialized_value)) return serialized_value - def to_form_field(self, set_initial=True): + def to_form_field(self, set_initial=True, enforce_required=True): """ Return a form field suitable for setting a CustomField's value for an object. - set_initial: Set initial date for the field. This should be false when generating a field for bulk editing. + set_initial: Set initial date for the field. This should be False when generating a field for bulk editing. + enforce_required: Honor the value of CustomField.required. Set to False for filtering/bulk editing. """ initial = self.default if set_initial else None + required = self.required if enforce_required else False # Integer if self.type == CustomFieldTypeChoices.TYPE_INTEGER: - field = forms.IntegerField(required=self.required, initial=initial) + field = forms.IntegerField(required=required, initial=initial) # Boolean elif self.type == CustomFieldTypeChoices.TYPE_BOOLEAN: @@ -308,19 +310,19 @@ class CustomField(models.Model): else: initial = None field = forms.NullBooleanField( - required=self.required, initial=initial, widget=StaticSelect2(choices=choices) + required=required, initial=initial, widget=StaticSelect2(choices=choices) ) # Date elif self.type == CustomFieldTypeChoices.TYPE_DATE: - field = forms.DateField(required=self.required, initial=initial, widget=DatePicker()) + field = forms.DateField(required=required, initial=initial, widget=DatePicker()) # Select elif self.type == CustomFieldTypeChoices.TYPE_SELECT: choices = [(cfc.pk, cfc.value) for cfc in self.choices.all()] # TODO: Accommodate bulk edit/filtering # if not self.required or bulk_edit or filterable_only: - if not self.required: + if not required: choices = add_blank_choice(choices) # Set the initial value to the PK of the default choice, if any if set_initial: @@ -328,16 +330,16 @@ class CustomField(models.Model): if default_choice: initial = default_choice.pk field = forms.TypedChoiceField( - choices=choices, coerce=int, required=self.required, initial=initial, widget=StaticSelect2() + choices=choices, coerce=int, required=required, initial=initial, widget=StaticSelect2() ) # URL elif self.type == CustomFieldTypeChoices.TYPE_URL: - field = LaxURLField(required=self.required, initial=initial) + field = LaxURLField(required=required, initial=initial) # Text else: - field = forms.CharField(max_length=255, required=self.required, initial=initial) + field = forms.CharField(max_length=255, required=required, initial=initial) field.model = self field.label = self.label if self.label else self.name.replace('_', ' ').capitalize()