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 typing import Any
from django.apps import AppConfig from django.apps import AppConfig
from django.template import Template
from django.utils.autoreload import file_changed, trigger_reload from django.utils.autoreload import file_changed, trigger_reload
@ -14,9 +15,15 @@ class ComponentsConfig(AppConfig):
def ready(self) -> None: def ready(self) -> None:
from django_components.app_settings import app_settings from django_components.app_settings import app_settings
from django_components.autodiscovery import autodiscover, import_libraries 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.component_registry import registry
from django_components.components.dynamic import DynamicComponent 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 modules set in `COMPONENTS.libraries` setting
import_libraries() import_libraries()

View file

@ -968,7 +968,7 @@ class ComponentNode(BaseNode):
return output 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` # Modify `Template.render` to set `isolated_context` kwarg of `push_state`
# based on our custom `Template._dc_is_component_nested`. # 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. # and can modify the rendering behavior by overriding the `_render` method.
# #
# NOTE 2: Instead of setting `Template._dc_is_component_nested`, alternatively we could # 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 # did NOT do that, so the monkey-patched method is more robust, and can be e.g. copied
# to other. # 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 # Do not patch if done so already. This helps us avoid RecursionError
return return
@ -1012,8 +1012,8 @@ def _monkeypatch_template(template: Template) -> None:
else: else:
return self._render(context, *args, **kwargs) return self._render(context, *args, **kwargs)
# See https://stackoverflow.com/a/42154067/9788634 template_cls.render = _template_render
template.render = types.MethodType(_template_render, template) template_cls._dc_patched = True
@contextmanager @contextmanager
@ -1037,7 +1037,14 @@ def _prepare_template(
# See https://github.com/EmilStenstrom/django-components/issues/580 # See https://github.com/EmilStenstrom/django-components/issues/580
# And https://github.com/EmilStenstrom/django-components/issues/634 # And https://github.com/EmilStenstrom/django-components/issues/634
template = component._get_template(context) 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 # Set `Template._dc_is_component_nested` based on whether we're currently INSIDE
# the `{% extends %}` tag. # the `{% extends %}` tag.