Skip to content

Commit

Permalink
fix: TemplateDoesNotExist when using {% extends %} on main template a…
Browse files Browse the repository at this point in the history
…nd two components with same parent template (#862)
  • Loading branch information
JuroOravec authored Dec 23, 2024
1 parent 6bb73bd commit 85fc6e3
Show file tree
Hide file tree
Showing 9 changed files with 876 additions and 394 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ poetry.lock
.DS_Store
.python-version
site
.direnv/
.envrc

# JS, NPM Dependency directories
node_modules/
Expand Down
5 changes: 5 additions & 0 deletions src/django_components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,10 @@ def _render_impl(
if not isinstance(context, Context):
context = RequestContext(request, context) if request else Context(context)

# Required for compatibility with Django's {% extends %} tag
# See https://github.com/EmilStenstrom/django-components/pull/859
context.render_context.push({BLOCK_CONTEXT_KEY: context.render_context.get(BLOCK_CONTEXT_KEY, {})})

# By adding the current input to the stack, we temporarily allow users
# to access the provided context, slots, etc. Also required so users can
# call `self.inject()` from within `get_context_data()`.
Expand Down Expand Up @@ -768,6 +772,7 @@ def _render_impl(
# After rendering is done, remove the current state from the stack, which means
# properties like `self.context` will no longer return the current state.
self._render_stack.pop()
context.render_context.pop()

return output

Expand Down
4 changes: 4 additions & 0 deletions src/django_components/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ def make_isolated_context_copy(context: Context) -> Context:
context_copy = context.new()
copy_forloop_context(context, context_copy)

# Required for compatibility with Django's {% extends %} tag
# See https://github.com/EmilStenstrom/django-components/pull/859
context_copy.render_context = context.render_context

# Pass through our internal keys
context_copy[_REGISTRY_CONTEXT_KEY] = context.get(_REGISTRY_CONTEXT_KEY, None)
if _ROOT_CTX_CONTEXT_KEY in context:
Expand Down
14 changes: 10 additions & 4 deletions src/django_components/slots.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,16 @@ def render(self, context: Context) -> SafeString:
# came from (or current context if configured so)
used_ctx = self._resolve_slot_context(context, slot_fill)
with used_ctx.update(extra_context):
# Render slot as a function
# NOTE: While `{% fill %}` tag has to opt in for the `default` and `data` variables,
# the render function ALWAYS receives them.
output = slot_fill.slot(used_ctx, kwargs, slot_ref)
# Required for compatibility with Django's {% extends %} tag
# This makes sure that the render context used outside of a component
# is the same as the one used inside the slot.
# See https://github.com/EmilStenstrom/django-components/pull/859
render_ctx_layer = used_ctx.render_context.dicts[-2] if len(used_ctx.render_context.dicts) > 1 else {}
with used_ctx.render_context.push(render_ctx_layer):
# Render slot as a function
# NOTE: While `{% fill %}` tag has to opt in for the `default` and `data` variables,
# the render function ALWAYS receives them.
output = slot_fill.slot(used_ctx, kwargs, slot_ref)

trace_msg("RENDR", "SLOT", self.trace_id, self.node_id, msg="...Done!")
return output
Expand Down
7 changes: 7 additions & 0 deletions tests/templates/blocked_and_slotted_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% load component_tags %}
{% block before_custom %}{% endblock %}
<custom-template>
<header>{% slot "header" %}Default header{% endslot %}</header>
<main>{% slot "main" %}Default main{% endslot %}</main>
<footer>{% slot "footer" %}Default footer{% endslot %}</footer>
</custom-template>
7 changes: 7 additions & 0 deletions tests/templates/blocked_and_slotted_template_2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% load component_tags %}
{% block before_custom %}{% endblock %}
<custom-template>
<header>{% slot "header" %}Default header{% endslot %}</header>
<main>{% slot "main" %}Default main{% endslot %}</main>
<footer>{% slot "footer" %}Default footer{% endslot %}</footer>
</custom-template>
4 changes: 4 additions & 0 deletions tests/templates/included.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{% extends "simple_template.html" %}
{% block before_custom %}
<div>BLOCK OVERRIDEN</div>
{% endblock %}
Loading

0 comments on commit 85fc6e3

Please sign in to comment.