refactor: apply Template patch at AppsConfig.ready() (#825)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Juro Oravec 2024-12-13 08:51:42 +01:00 committed by GitHub
parent a5659691d0
commit db4ca8b74f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 20 additions and 6 deletions

View file

@ -3,6 +3,7 @@ from pathlib import Path
from typing import Any
from django.apps import AppConfig
from django.template import Template
from django.utils.autoreload import file_changed, trigger_reload
@ -14,9 +15,15 @@ class ComponentsConfig(AppConfig):
def ready(self) -> None:
from django_components.app_settings import app_settings
from django_components.autodiscovery import autodiscover, import_libraries
from django_components.component import monkeypatch_template
from django_components.component_registry import registry
from django_components.components.dynamic import DynamicComponent
# NOTE: This monkeypatch is applied here, before Django processes any requests.
# To make django-components work with django-debug-toolbar-template-profiler
# See https://github.com/EmilStenstrom/django-components/discussions/819
monkeypatch_template(Template)
# Import modules set in `COMPONENTS.libraries` setting
import_libraries()

View file

@ -968,7 +968,7 @@ class ComponentNode(BaseNode):
return output
def _monkeypatch_template(template: Template) -> None:
def monkeypatch_template(template_cls: Type[Template]) -> None:
# Modify `Template.render` to set `isolated_context` kwarg of `push_state`
# based on our custom `Template._dc_is_component_nested`.
#
@ -986,10 +986,10 @@ def _monkeypatch_template(template: Template) -> None:
# and can modify the rendering behavior by overriding the `_render` method.
#
# NOTE 2: Instead of setting `Template._dc_is_component_nested`, alternatively we could
# have passed the value to `_monkeypatch_template` directly. However, we intentionally
# have passed the value to `monkeypatch_template` directly. However, we intentionally
# did NOT do that, so the monkey-patched method is more robust, and can be e.g. copied
# to other.
if hasattr(template, "_dc_patched"):
if hasattr(template_cls, "_dc_patched"):
# Do not patch if done so already. This helps us avoid RecursionError
return
@ -1012,8 +1012,8 @@ def _monkeypatch_template(template: Template) -> None:
else:
return self._render(context, *args, **kwargs)
# See https://stackoverflow.com/a/42154067/9788634
template.render = types.MethodType(_template_render, template)
template_cls.render = _template_render
template_cls._dc_patched = True
@contextmanager
@ -1037,7 +1037,14 @@ def _prepare_template(
# See https://github.com/EmilStenstrom/django-components/issues/580
# And https://github.com/EmilStenstrom/django-components/issues/634
template = component._get_template(context)
_monkeypatch_template(template)
if not getattr(template, "_dc_patched"):
raise RuntimeError(
"Django-components received a Template instance which was not patched."
"If you are using Django's Template class, check if you added django-components"
"to INSTALLED_APPS. If you are using a custom template class, then you need to"
"manually patch the class."
)
# Set `Template._dc_is_component_nested` based on whether we're currently INSIDE
# the `{% extends %}` tag.