mirror of
https://github.com/django-components/django-components.git
synced 2025-09-18 11:49:44 +00:00
fix: fix compat with extends and includes (#1344)
This commit is contained in:
parent
a6e840bdca
commit
9be4124339
6 changed files with 88 additions and 5 deletions
|
@ -1,5 +1,12 @@
|
||||||
# Release notes
|
# Release notes
|
||||||
|
|
||||||
|
## v0.141.4
|
||||||
|
|
||||||
|
#### Fix
|
||||||
|
|
||||||
|
- Fix compatibility with Django's `{% include %}` and `{% extends %}` tags.
|
||||||
|
See https://github.com/django-components/django-components/issues/1325
|
||||||
|
|
||||||
## v0.141.3
|
## v0.141.3
|
||||||
|
|
||||||
#### Feat
|
#### Feat
|
||||||
|
|
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "django_components"
|
name = "django_components"
|
||||||
version = "0.141.3"
|
version = "0.141.4"
|
||||||
requires-python = ">=3.8, <4.0"
|
requires-python = ">=3.8, <4.0"
|
||||||
description = "A way to create simple reusable template components in Django."
|
description = "A way to create simple reusable template components in Django."
|
||||||
keywords = ["django", "components", "css", "js", "html"]
|
keywords = ["django", "components", "css", "js", "html"]
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import difflib
|
import difflib
|
||||||
import re
|
import re
|
||||||
|
from contextlib import contextmanager
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from dataclasses import replace as dataclass_replace
|
from dataclasses import replace as dataclass_replace
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
Dict,
|
Dict,
|
||||||
|
Generator,
|
||||||
Generic,
|
Generic,
|
||||||
List,
|
List,
|
||||||
Literal,
|
Literal,
|
||||||
|
@ -1460,8 +1462,10 @@ def _extract_fill_content(
|
||||||
# When, during rendering of this tree, we encounter a {% fill %} node, instead of rendering content,
|
# When, during rendering of this tree, we encounter a {% fill %} node, instead of rendering content,
|
||||||
# it will add itself into captured_fills, because `FILL_GEN_CONTEXT_KEY` is defined.
|
# it will add itself into captured_fills, because `FILL_GEN_CONTEXT_KEY` is defined.
|
||||||
captured_fills: List[FillWithData] = []
|
captured_fills: List[FillWithData] = []
|
||||||
with context.update({FILL_GEN_CONTEXT_KEY: captured_fills}):
|
|
||||||
content = mark_safe(nodes.render(context).strip())
|
with _extends_context_reset(context):
|
||||||
|
with context.update({FILL_GEN_CONTEXT_KEY: captured_fills}):
|
||||||
|
content = mark_safe(nodes.render(context).strip())
|
||||||
|
|
||||||
# If we did not encounter any fills (not accounting for those nested in other
|
# If we did not encounter any fills (not accounting for those nested in other
|
||||||
# {% componenet %} tags), then we treat the content as default slot.
|
# {% componenet %} tags), then we treat the content as default slot.
|
||||||
|
@ -1667,3 +1671,24 @@ def _nodelist_to_slot(
|
||||||
|
|
||||||
def _is_extracting_fill(context: Context) -> bool:
|
def _is_extracting_fill(context: Context) -> bool:
|
||||||
return context.get(FILL_GEN_CONTEXT_KEY, None) is not None
|
return context.get(FILL_GEN_CONTEXT_KEY, None) is not None
|
||||||
|
|
||||||
|
|
||||||
|
# Fix for compatibility with Django's `{% include %}` and `{% extends %}` tags.
|
||||||
|
# See https://github.com/django-components/django-components/issues/1325
|
||||||
|
#
|
||||||
|
# When we search for `{% fill %}` tags, we also evaluate `{% include %}` and `{% extends %}`
|
||||||
|
# tags if they are within component body (between `{% component %}` / `{% endcomponent %}` tags).
|
||||||
|
# But by doing so, we trigger Django's block/extends logic to remember that this extended file
|
||||||
|
# was already walked.
|
||||||
|
# (See https://github.com/django/django/blob/0bff53b4138d8c6009e9040dbb8916a1271a68d7/django/template/loader_tags.py#L114) # noqa: E501
|
||||||
|
#
|
||||||
|
# We need to clear that state, otherwise Django won't render the extended template the second time
|
||||||
|
# (when we actually render it).
|
||||||
|
@contextmanager
|
||||||
|
def _extends_context_reset(context: Context) -> Generator[None, None, None]:
|
||||||
|
b4_ctx_extends = context.render_context.setdefault("extends_context", []).copy()
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
# Reset the state of what extends have been seen.
|
||||||
|
context.render_context["extends_context"] = b4_ctx_extends
|
||||||
|
|
4
tests/templates/extends_compat_c_include.html
Normal file
4
tests/templates/extends_compat_c_include.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends "extends_compat_d_extended.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<p>This template extends another template.</p>
|
||||||
|
{% endblock %}
|
3
tests/templates/extends_compat_d_extended.html
Normal file
3
tests/templates/extends_compat_d_extended.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<p>This template gets extended.</p>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
|
@ -145,7 +145,9 @@ class TestExtendsCompat:
|
||||||
assertHTMLEqual(rendered, expected)
|
assertHTMLEqual(rendered, expected)
|
||||||
|
|
||||||
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
|
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
|
||||||
def test_double_extends_on_main_template_and_component_two_different_components_same_parent(self, components_settings): # noqa: E501
|
def test_double_extends_on_main_template_and_component_two_different_components_same_parent(
|
||||||
|
self, components_settings
|
||||||
|
):
|
||||||
registry.register("blocked_and_slotted_component", gen_blocked_and_slotted_component())
|
registry.register("blocked_and_slotted_component", gen_blocked_and_slotted_component())
|
||||||
|
|
||||||
@register("extended_component")
|
@register("extended_component")
|
||||||
|
@ -211,7 +213,9 @@ class TestExtendsCompat:
|
||||||
assertHTMLEqual(rendered, expected)
|
assertHTMLEqual(rendered, expected)
|
||||||
|
|
||||||
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
|
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
|
||||||
def test_double_extends_on_main_template_and_component_two_different_components_different_parent(self, components_settings): # noqa: E501
|
def test_double_extends_on_main_template_and_component_two_different_components_different_parent(
|
||||||
|
self, components_settings
|
||||||
|
):
|
||||||
registry.register("blocked_and_slotted_component", gen_blocked_and_slotted_component())
|
registry.register("blocked_and_slotted_component", gen_blocked_and_slotted_component())
|
||||||
|
|
||||||
@register("extended_component")
|
@register("extended_component")
|
||||||
|
@ -1029,3 +1033,43 @@ class TestExtendsCompat:
|
||||||
</html>
|
</html>
|
||||||
"""
|
"""
|
||||||
assertHTMLEqual(rendered, expected)
|
assertHTMLEqual(rendered, expected)
|
||||||
|
|
||||||
|
# Fix for compatibility with Django's `{% include %}` and `{% extends %}` tags.
|
||||||
|
# See https://github.com/django-components/django-components/issues/1325
|
||||||
|
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
|
||||||
|
def test_nested_component_with_include_and_extends_in_slot(self, components_settings):
|
||||||
|
@register("a_outer")
|
||||||
|
class AOuterComponent(Component):
|
||||||
|
template: types.django_html = """
|
||||||
|
{% load component_tags %}
|
||||||
|
<p>This is the outer component.</p>
|
||||||
|
{% slot "a" default / %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
@register("b_inner")
|
||||||
|
class BInnerComponent(Component):
|
||||||
|
template: types.django_html = """
|
||||||
|
{% load component_tags %}
|
||||||
|
<p>This is the inner component.</p>
|
||||||
|
{% slot "b" default / %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
template: types.django_html = """
|
||||||
|
{% load component_tags %}
|
||||||
|
{% component "a_outer" %}
|
||||||
|
{% component "b_inner" %}
|
||||||
|
{% include "extends_compat_c_include.html" %}
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endcomponent %}
|
||||||
|
"""
|
||||||
|
rendered = Template(template).render(Context({}))
|
||||||
|
|
||||||
|
assertHTMLEqual(
|
||||||
|
rendered,
|
||||||
|
"""
|
||||||
|
<p data-djc-id-ca1bc40>This is the outer component.</p>
|
||||||
|
<p data-djc-id-ca1bc40 data-djc-id-ca1bc42>This is the inner component.</p>
|
||||||
|
<p data-djc-id-ca1bc40 data-djc-id-ca1bc42>This template gets extended.</p>
|
||||||
|
<p data-djc-id-ca1bc40 data-djc-id-ca1bc42>This template extends another template.</p>
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue