From ece60ad3b198f31e43437507aae4298b8937b9b8 Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Thu, 6 Nov 2025 16:14:02 +0100 Subject: [PATCH] Implement default values in custom forms --- src/servala/core/crd/forms.py | 3 + .../core/schemas/form_config_schema.json | 4 + src/tests/test_form_config.py | 114 ++++++++++++++++++ 3 files changed, 121 insertions(+) diff --git a/src/servala/core/crd/forms.py b/src/servala/core/crd/forms.py index 6eb8c74..99e2737 100644 --- a/src/servala/core/crd/forms.py +++ b/src/servala/core/crd/forms.py @@ -318,6 +318,9 @@ class CustomFormMixin(FormGeneratorMixin): if validators: field.validators.extend(validators) + if "default_value" in field_config and field.initial is None: + field.initial = field_config["default_value"] + field.controlplane_field_mapping = field_name def get_fieldsets(self): diff --git a/src/servala/core/schemas/form_config_schema.json b/src/servala/core/schemas/form_config_schema.json index 62fa91b..4cdc061 100644 --- a/src/servala/core/schemas/form_config_schema.json +++ b/src/servala/core/schemas/form_config_schema.json @@ -92,6 +92,10 @@ "type": "string", "enum": ["email", "fqdn", "url", "ipv4", "ipv6"] } + }, + "default_value": { + "type": "string", + "description": "Default value for the field when creating new instances" } } } diff --git a/src/tests/test_form_config.py b/src/tests/test_form_config.py index 3b6a197..0228107 100644 --- a/src/tests/test_form_config.py +++ b/src/tests/test_form_config.py @@ -519,3 +519,117 @@ def test_number_field_min_max_sets_widget_attributes(): isinstance(v, MaxValueValidator) and v.limit_value == 65535 for v in port_validators ) + + +def test_default_value_for_all_field_types(): + + class TestModel(models.Model): + name = models.CharField(max_length=100) + description = models.TextField() + port = models.IntegerField() + environment = models.CharField( + max_length=20, + choices=[ + ("dev", "Development"), + ("staging", "Staging"), + ("prod", "Production"), + ], + ) + monitoring_enabled = models.BooleanField() + tags = models.JSONField() + + class Meta: + app_label = "test" + + form_config = { + "fieldsets": [ + { + "fields": [ + { + "type": "text", + "label": "Name", + "controlplane_field_mapping": "name", + "default_value": "default-name", + }, + { + "type": "textarea", + "label": "Description", + "controlplane_field_mapping": "description", + "default_value": "Default description text", + }, + { + "type": "number", + "label": "Port", + "controlplane_field_mapping": "port", + "default_value": "8080", + }, + { + "type": "choice", + "label": "Environment", + "controlplane_field_mapping": "environment", + "default_value": "dev", + }, + { + "type": "checkbox", + "label": "Enable Monitoring", + "controlplane_field_mapping": "monitoring_enabled", + "default_value": "true", + }, + { + "type": "array", + "label": "Tags", + "controlplane_field_mapping": "tags", + "default_value": "tag1,tag2,tag3", + }, + ], + } + ] + } + + form_class = generate_custom_form_class(form_config, TestModel) + form = form_class() + + assert form.fields["name"].initial == "default-name" + assert form.fields["description"].initial == "Default description text" + assert form.fields["port"].initial == "8080" + assert form.fields["environment"].initial == "dev" + assert form.fields["monitoring_enabled"].initial == "true" + assert form.fields["tags"].initial == "tag1,tag2,tag3" + + +def test_default_value_not_override_existing_instance(): + + class TestModel(models.Model): + name = models.CharField(max_length=100) + port = models.IntegerField() + + class Meta: + app_label = "test" + + form_config = { + "fieldsets": [ + { + "fields": [ + { + "type": "text", + "label": "Name", + "controlplane_field_mapping": "name", + "default_value": "default-name", + }, + { + "type": "number", + "label": "Port", + "controlplane_field_mapping": "port", + "default_value": "8080", + }, + ], + } + ] + } + + instance = TestModel(name="existing-name", port=3000) + form_class = generate_custom_form_class(form_config, TestModel) + form = form_class(instance=instance) + + assert form.initial["name"] == "existing-name" + assert form.initial["port"] == 3000