Closes #14656: Dynamically render form fields depending on custom field type (#17068)

This commit is contained in:
Jeremy Stretch 2024-08-02 08:14:01 -04:00 committed by GitHub
parent 472fbdc654
commit f3da529399
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -45,32 +45,35 @@ __all__ = (
class CustomFieldForm(forms.ModelForm): class CustomFieldForm(forms.ModelForm):
object_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_fields') queryset=ObjectType.objects.with_feature('custom_fields'),
help_text=_("The type(s) of object that have this custom field")
)
default = JSONField(
label=_('Default value'),
required=False
) )
related_object_type = ContentTypeChoiceField( related_object_type = ContentTypeChoiceField(
label=_('Related object type'), label=_('Related object type'),
queryset=ObjectType.objects.public(), queryset=ObjectType.objects.public(),
required=False,
help_text=_("Type of the related object (for object/multi-object fields only)") help_text=_("Type of the related object (for object/multi-object fields only)")
) )
choice_set = DynamicModelChoiceField( related_object_filter = JSONField(
queryset=CustomFieldChoiceSet.objects.all(), label=_('Related object filter'),
required=False required=False
) )
choice_set = DynamicModelChoiceField(
queryset=CustomFieldChoiceSet.objects.all()
)
comments = CommentField() comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
'object_types', 'name', 'label', 'group_name', 'type', 'related_object_type', 'required', 'description', 'object_types', 'name', 'label', 'group_name', 'description', 'type', 'required', 'validation_unique',
name=_('Custom Field') 'default', name=_('Custom Field')
), ),
FieldSet( FieldSet(
'search_weight', 'filter_logic', 'ui_visible', 'ui_editable', 'weight', 'is_cloneable', name=_('Behavior') 'search_weight', 'filter_logic', 'ui_visible', 'ui_editable', 'weight', 'is_cloneable', name=_('Behavior')
), ),
FieldSet('default', 'choice_set', 'related_object_filter', name=_('Values')),
FieldSet(
'validation_minimum', 'validation_maximum', 'validation_regex', 'validation_unique', name=_('Validation')
),
) )
class Meta: class Meta:
@ -87,11 +90,75 @@ class CustomFieldForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# Mimic HTMXSelect()
self.fields['type'].widget.attrs.update({
'hx-get': '.',
'hx-include': '#form_fields',
'hx-target': '#form_fields',
})
# Disable changing the type of a CustomField as it almost universally causes errors if custom field data # Disable changing the type of a CustomField as it almost universally causes errors if custom field data
# is already present. # is already present.
if self.instance.pk: if self.instance.pk:
self.fields['type'].disabled = True self.fields['type'].disabled = True
field_type = get_field_value(self, 'type')
# Adjust for text fields
if field_type in (
CustomFieldTypeChoices.TYPE_TEXT,
CustomFieldTypeChoices.TYPE_LONGTEXT,
CustomFieldTypeChoices.TYPE_URL
):
self.fieldsets = (
self.fieldsets[0],
FieldSet('validation_regex', name=_('Validation')),
*self.fieldsets[1:]
)
else:
del self.fields['validation_regex']
# Adjust for numeric fields
if field_type in (
CustomFieldTypeChoices.TYPE_INTEGER,
CustomFieldTypeChoices.TYPE_DECIMAL
):
self.fieldsets = (
self.fieldsets[0],
FieldSet('validation_minimum', 'validation_maximum', name=_('Validation')),
*self.fieldsets[1:]
)
else:
del self.fields['validation_minimum']
del self.fields['validation_maximum']
# Adjust for object & multi-object fields
if field_type in (
CustomFieldTypeChoices.TYPE_OBJECT,
CustomFieldTypeChoices.TYPE_MULTIOBJECT
):
self.fieldsets = (
self.fieldsets[0],
FieldSet('related_object_type', 'related_object_filter', name=_('Related Object')),
*self.fieldsets[1:]
)
else:
del self.fields['related_object_type']
del self.fields['related_object_filter']
# Adjust for selection & multi-select fields
if field_type in (
CustomFieldTypeChoices.TYPE_SELECT,
CustomFieldTypeChoices.TYPE_MULTISELECT
):
self.fieldsets = (
self.fieldsets[0],
FieldSet('choice_set', name=_('Choices')),
*self.fieldsets[1:]
)
else:
del self.fields['choice_set']
class CustomFieldChoiceSetForm(forms.ModelForm): class CustomFieldChoiceSetForm(forms.ModelForm):
extra_choices = forms.CharField( extra_choices = forms.CharField(