Patch TemplateProxy to restore compatibility with template_partials (#1328)

Co-authored-by: EmilStenstrom <224130+EmilStenstrom@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Juro Oravec <juraj.oravec.josefson@gmail.com>
This commit is contained in:
Copilot 2025-08-14 11:00:56 +02:00 committed by GitHub
parent e9b7470850
commit aa14e3698d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 159 additions and 13 deletions

View file

@ -19,7 +19,11 @@ class ComponentsConfig(AppConfig):
from django_components.component_registry import registry
from django_components.components.dynamic import DynamicComponent
from django_components.extension import extensions
from django_components.util.django_monkeypatch import monkeypatch_include_node, monkeypatch_template_cls
from django_components.util.django_monkeypatch import (
monkeypatch_include_node,
monkeypatch_template_cls,
monkeypatch_template_proxy_cls,
)
# NOTE: This monkeypatch is applied here, before Django processes any requests.
# To make django-components work with django-debug-toolbar-template-profiler
@ -27,6 +31,10 @@ class ComponentsConfig(AppConfig):
monkeypatch_template_cls(Template)
monkeypatch_include_node(IncludeNode)
# This makes django-components work with django-template-partials
# NOTE: Delete when Django 5.2 reaches end of life
monkeypatch_template_proxy_cls()
# Import modules set in `COMPONENTS.libraries` setting
import_libraries()

View file

@ -3250,7 +3250,7 @@ class Component(metaclass=ComponentMeta):
),
)
```
""" # noqa: 501
""" # noqa: E501
# TODO_v1 - Remove, superseded by `deps_strategy`
if type is not None:

View file

@ -1,5 +1,6 @@
from typing import Any, Optional, Type
from django import VERSION as DJANGO_VERSION
from django.template import Context, NodeList, Template
from django.template.base import Node, Origin, Parser
from django.template.loader_tags import IncludeNode
@ -117,10 +118,14 @@ def monkeypatch_template_compile_nodelist(template_cls: Type[Template]) -> None:
)
try:
# ---------------- ADDED IN Django v5.1 - See https://github.com/django/django/commit/35bbb2c9c01882b1d77b0b8c737ac646144833d4 # noqa: E501
nodelist = parser.parse()
self.extra_data = getattr(parser, "extra_data", {})
# ---------------- END OF ADDED IN Django v5.1 ----------------
if DJANGO_VERSION >= (5, 1):
# ---------------- ADDED IN Django v5.1 - See https://github.com/django/django/commit/35bbb2c9c01882b1d77b0b8c737ac646144833d4 # noqa: E501
# NOTE: This must be enabled ONLY for 5.1 and later. Previously it was also for older
# Django versions, and this led to compatibility issue with django-template-partials.
# See https://github.com/carltongibson/django-template-partials/pull/85#issuecomment-3187354790
self.extra_data = getattr(parser, "extra_data", {})
# ---------------- END OF ADDED IN Django v5.1 ----------------
return nodelist
except Exception as e:
if self.engine.debug:
@ -243,5 +248,33 @@ def monkeypatch_include_render(include_node_cls: Type[Node]) -> None:
include_node_cls.render = _include_render
# NOTE: Remove once Django v5.2 reaches end of life
# See https://github.com/django-components/django-components/issues/1323#issuecomment-3163478287
def monkeypatch_template_proxy_cls() -> None:
# Patch TemplateProxy if template_partials is installed
# See https://github.com/django-components/django-components/issues/1323#issuecomment-3164224042
try:
from template_partials.templatetags.partials import TemplateProxy
except ImportError:
# template_partials is in INSTALLED_APPS but not actually installed
# This is fine, just skip the patching
return
if is_cls_patched(TemplateProxy):
return
monkeypatch_template_proxy_render(TemplateProxy)
TemplateProxy._djc_patched = True
def monkeypatch_template_proxy_render(template_proxy_cls: Type[Any]) -> None:
# NOTE: TemplateProxy.render() is same logic as Template.render(), just duplicated.
# So we can instead reuse Template.render()
def _template_proxy_render(self: Any, context: Context, *args: Any, **kwargs: Any) -> str:
return Template.render(self, context)
template_proxy_cls.render = _template_proxy_render
def is_cls_patched(cls: Type[Any]) -> bool:
return getattr(cls, "_djc_patched", False)