diff --git a/src/unfold/templates/unfold/helpers/fieldset_row.html b/src/unfold/templates/unfold/helpers/fieldset_row.html index 1722b84f4..a19f4c230 100644 --- a/src/unfold/templates/unfold/helpers/fieldset_row.html +++ b/src/unfold/templates/unfold/helpers/fieldset_row.html @@ -3,7 +3,7 @@
{% for field in line %} {% with adminform.model_admin.conditional_fields|index:field.field.name as conditional_display %} -
+
{% if has_conditional_display %} {% with field|changeform_condition as field %} {% if field.is_checkbox %} diff --git a/tests/conftest.py b/tests/conftest.py index 40b983e3b..b3b23a21f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,8 @@ from pytest_factoryboy import register -from .factories import TagFactory, UserFactory +from .factories import ConditionalFieldsTestModelFactory, TagFactory, UserFactory from .fixtures import * # noqa: F403 register(TagFactory) register(UserFactory) +register(ConditionalFieldsTestModelFactory) diff --git a/tests/factories.py b/tests/factories.py index 89ce270ae..dd433fdda 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -1,4 +1,5 @@ -from example.models import Tag, User +import factory +from example.models import ConditionalFieldsTestModel, Tag, User from factory.django import DjangoModelFactory @@ -10,3 +11,12 @@ class Meta: class TagFactory(DjangoModelFactory): class Meta: model = Tag + + +class ConditionalFieldsTestModelFactory(DjangoModelFactory): + class Meta: + model = ConditionalFieldsTestModel + + name = factory.Faker("name") + conditional_field_active = factory.Faker("name") + conditional_field_inactive = factory.Faker("name") diff --git a/tests/server/example/admin.py b/tests/server/example/admin.py index f3958d689..e61e2d320 100644 --- a/tests/server/example/admin.py +++ b/tests/server/example/admin.py @@ -10,7 +10,7 @@ from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm from unfold.sections import TableSection, TemplateSection -from .models import ActionUser, SectionUser, Tag, User +from .models import ActionUser, ConditionalFieldsTestModel, SectionUser, Tag, User admin.site.unregister(Group) @@ -52,6 +52,22 @@ class SectionUserAdmin(UserAdmin): ] +@admin.register(ConditionalFieldsTestModel) +class ConditionalFieldsModelAdmin(ModelAdmin): + list_display = ["name", "status"] + fields = [ + "name", + "status", + "conditional_field_active", + "conditional_field_inactive", + ] + + conditional_fields = { + "conditional_field_active": 'status === "ACTIVE"', + "conditional_field_inactive": 'status === "INACTIVE"', + } + + @admin.register(ActionUser) class ActionsUserAdmin(BaseUserAdmin, ModelAdmin): form = UserChangeForm diff --git a/tests/server/example/migrations/0005_conditionalfieldstestmodel.py b/tests/server/example/migrations/0005_conditionalfieldstestmodel.py new file mode 100644 index 000000000..852428501 --- /dev/null +++ b/tests/server/example/migrations/0005_conditionalfieldstestmodel.py @@ -0,0 +1,51 @@ +# Generated by Django 4.2.22 on 2025-08-26 07:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("example", "0004_actionuser_sectionuser"), + ] + + operations = [ + migrations.CreateModel( + name="ConditionalFieldsTestModel", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=100)), + ( + "status", + models.CharField( + choices=[("ACTIVE", "Active"), ("INACTIVE", "Inactive")], + default="ACTIVE", + max_length=10, + ), + ), + ( + "conditional_field_active", + models.CharField( + blank=True, + help_text="This field is only visible when status is ACTIVE", + max_length=100, + ), + ), + ( + "conditional_field_inactive", + models.CharField( + blank=True, + help_text="This field is only visible when status is INACTIVE", + max_length=100, + ), + ), + ], + ), + ] diff --git a/tests/server/example/models.py b/tests/server/example/models.py index ac43dc16c..939f53ad9 100644 --- a/tests/server/example/models.py +++ b/tests/server/example/models.py @@ -24,3 +24,25 @@ class Tag(models.Model): def __str__(self): return self.name + + +class ConditionalFieldsTestModel(models.Model): + STATUS_CHOICES = ( + ("ACTIVE", "Active"), + ("INACTIVE", "Inactive"), + ) + name = models.CharField(max_length=100) + status = models.CharField(max_length=10, choices=STATUS_CHOICES, default="ACTIVE") + conditional_field_active = models.CharField( + max_length=100, + blank=True, + help_text="This field is only visible when status is ACTIVE", + ) + conditional_field_inactive = models.CharField( + max_length=100, + blank=True, + help_text="This field is only visible when status is INACTIVE", + ) + + def __str__(self): + return self.name diff --git a/tests/test_conditional_fields.py b/tests/test_conditional_fields.py new file mode 100644 index 000000000..db7d73d61 --- /dev/null +++ b/tests/test_conditional_fields.py @@ -0,0 +1,34 @@ +import re +from http import HTTPStatus + +import pytest +from django.urls import reverse + +from tests.factories import ConditionalFieldsTestModelFactory + + +@pytest.mark.django_db +def test_conditional_fields_in_context(admin_client): + """Test that conditional fields are properly included in the admin form context.""" + conditional_fields_test_instance = ConditionalFieldsTestModelFactory( + status="ACTIVE", + conditional_field_active="Active Value", + conditional_field_inactive="Inactive Value", + ) + change_url = reverse( + "admin:example_conditionalfieldstestmodel_change", + args=[conditional_fields_test_instance.pk], + ) + + response = admin_client.get(change_url) + + assert response.status_code == HTTPStatus.OK + content = response.content.decode() + # Test that the x-bind:disabled directive is present to disable hidden fields + assert re.search( + r'x-bind:disabled="!\(status\s*===\s*"ACTIVE"\)"', content + ) + assert re.search( + r'x-bind:disabled="!\(status\s*===\s*"INACTIVE"\)"', content + ) + # TODO: test that the fields are disabled (at init & on update)