diff --git a/src/django_components/slots.py b/src/django_components/slots.py index 874e8a67..fa9c3fa3 100644 --- a/src/django_components/slots.py +++ b/src/django_components/slots.py @@ -461,7 +461,17 @@ def _resolve_default_slot( # Here we've identified which slot the default/implicit fill belongs to if default_fill: - named_fills[slot.name] = default_fill._replace(name=slot.name) + # NOTE: We recreate new instance, passing all fields, instead of using + # `NamedTuple._replace`, because `_replace` is not typed. + named_fills[slot.name] = SlotFill( + is_filled=default_fill.is_filled, + nodelist=default_fill.nodelist, + context_data=default_fill.context_data, + alias=default_fill.alias, + # Updated fields + name=slot.name, + escaped_name=_escape_slot_name(slot.name), + ) # Check: Only component templates that include a 'default' slot # can be invoked with implicit filling. diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py index 364baa2f..4793ff04 100644 --- a/tests/test_templatetags.py +++ b/tests/test_templatetags.py @@ -1157,7 +1157,7 @@ class ComponentNestingTests(BaseTestCase): class ComplexParentComponent(component.Component): template: types.django_html = """ {% load component_tags %} - ITEMS: {{ items }} + ITEMS: {{ items|safe }} {% for item in items %}
  • {% component "complex_child" %} @@ -1296,7 +1296,7 @@ class ComponentNestingTests(BaseTestCase): items = [{"value": 1}, {"value": 2}, {"value": 3}] rendered = template.render(Context({"items": items})) expected = """ - ITEMS: [{'value': 1}, {'value': 2}, {'value': 3}] + ITEMS: [{'value': 1}, {'value': 2}, {'value': 3}]
  • 1
  • @@ -1522,12 +1522,12 @@ class ContextVarsTests(BaseTestCase): template: types.django_html = """ {% load component_tags %}
    - {% slot "title" %}{% endslot %} + {% slot "title" default %}{% endslot %} {% slot "my_title" %}{% endslot %} {% slot "my title 1" %}{% endslot %} {% slot "my-title-2" %}{% endslot %} {% slot "escape this: #$%^*()" %}{% endslot %} - {{ component_vars.is_filled }} + {{ component_vars.is_filled|safe }}
    """ @@ -1546,14 +1546,33 @@ class ContextVarsTests(BaseTestCase): {% endcomponent %} """ rendered = Template(template).render(Context()) - # NOTE: `'` are escaped quotes expected = """
    - {'title': True, - 'my_title': False, - 'my_title_1': False, - 'my_title_2': True, - 'escape_this_________': True} + {'title': True, + 'my_title': False, + 'my_title_1': False, + 'my_title_2': True, + 'escape_this_________': True} +
    + """ + self.assertHTMLEqual(rendered, expected) + + def test_is_filled_vars_default(self): + template: types.django_html = """ + {% load component_tags %} + {% component "is_filled_vars" %} + bla bla + {% endcomponent %} + """ + rendered = Template(template).render(Context()) + expected = """ +
    + bla bla + {'title': True, + 'my_title': False, + 'my_title_1': False, + 'my_title_2': False, + 'escape_this_________': False}
    """ self.assertHTMLEqual(rendered, expected) @@ -2337,10 +2356,10 @@ class IterationFillTest(BaseTestCase): {% load component_tags %} {% component "slot_in_a_loop" objects=objects %} {% fill "slot_inner" %} - {{ outer_scope_variable_1 }} + {{ outer_scope_variable_1|safe }} {% component "slot_in_a_loop" objects=objects %} {% fill "slot_inner" as "super_slot_inner" %} - {{ outer_scope_variable_2 }} + {{ outer_scope_variable_2|safe }} {{ super_slot_inner.default }} {% endfill %} {% endcomponent %} @@ -2363,13 +2382,13 @@ class IterationFillTest(BaseTestCase): """ OUTER_SCOPE_VARIABLE1 OUTER_SCOPE_VARIABLE2 - {'inner': ['ITER1_OBJ1', 'ITER1_OBJ2']} default + {'inner': ['ITER1_OBJ1', 'ITER1_OBJ2']} default OUTER_SCOPE_VARIABLE2 - {'inner': ['ITER2_OBJ1', 'ITER2_OBJ2']} default + {'inner': ['ITER2_OBJ1', 'ITER2_OBJ2']} default OUTER_SCOPE_VARIABLE1 OUTER_SCOPE_VARIABLE2 - {'inner': ['ITER1_OBJ1', 'ITER1_OBJ2']} default + {'inner': ['ITER1_OBJ1', 'ITER1_OBJ2']} default OUTER_SCOPE_VARIABLE2 - {'inner': ['ITER2_OBJ1', 'ITER2_OBJ2']} default + {'inner': ['ITER2_OBJ1', 'ITER2_OBJ2']} default """, )