",
+ views.view_to_component_iframe,
+ name="view_to_component",
+ ),
]
diff --git a/src/django_idom/http/views.py b/src/django_idom/http/views.py
index 4134c058..9623cb2f 100644
--- a/src/django_idom/http/views.py
+++ b/src/django_idom/http/views.py
@@ -1,11 +1,13 @@
import os
+from inspect import isclass, iscoroutinefunction
from aiofile import async_open
+from channels.db import database_sync_to_async
from django.core.exceptions import SuspiciousOperation
from django.http import HttpRequest, HttpResponse
from idom.config import IDOM_WED_MODULES_DIR
-from django_idom.config import IDOM_CACHE
+from django_idom.config import IDOM_CACHE, IDOM_REGISTERED_IFRAMES
async def web_modules_file(request: HttpRequest, file: str) -> HttpResponse:
@@ -32,3 +34,22 @@ async def web_modules_file(request: HttpRequest, file: str) -> HttpResponse:
cache_key, response, timeout=None, version=last_modified_time
)
return response
+
+
+async def view_to_component_iframe(view_path: str) -> HttpResponse:
+ """Returns a Django view that was registered by view_to_component.
+ This is used by `view_to_component` to render the view within an iframe."""
+ # Get the view from IDOM_REGISTERED_IFRAMES
+ iframe = IDOM_REGISTERED_IFRAMES.get(view_path)
+ if not iframe:
+ raise ValueError(f"No view registered for component {view_path}.")
+
+ # Render the view
+ # TODO: Apply middleware using some helper function~
+ if isclass(iframe):
+ return await database_sync_to_async(iframe.view.as_view())()
+
+ if iscoroutinefunction(iframe):
+ return await iframe.view()
+
+ return await database_sync_to_async(iframe.view)()
diff --git a/src/django_idom/types.py b/src/django_idom/types.py
new file mode 100644
index 00000000..52efa461
--- /dev/null
+++ b/src/django_idom/types.py
@@ -0,0 +1,14 @@
+from dataclasses import dataclass
+from typing import Callable, Tuple
+
+from django.views.generic import View
+from idom.core.component import Component
+
+
+@dataclass
+class ViewToComponentIframe:
+ middleware: list[Callable | str]
+ view: View | Callable
+ component: Component | object
+ args: Tuple
+ kwargs: dict
From bb8ea09ba26bda2d30d92d26ee090648717f0c94 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 15:46:28 -0700
Subject: [PATCH 029/110] functional compatibility mode
---
src/django_idom/__init__.py | 4 +-
src/django_idom/config.py | 4 +-
src/django_idom/decorators.py | 59 -----------------
src/django_idom/http/views.py | 14 ++--
src/django_idom/types.py | 4 +-
src/django_idom/utils.py | 65 ++++++++++++++++++-
tests/test_app/components.py | 29 +++++++++
tests/test_app/settings.py | 1 +
tests/test_app/templates/base.html | 5 ++
.../test_app/templates/view_to_component.html | 2 +
tests/test_app/views.py | 27 ++++++++
11 files changed, 141 insertions(+), 73 deletions(-)
delete mode 100644 src/django_idom/decorators.py
create mode 100644 tests/test_app/templates/view_to_component.html
diff --git a/src/django_idom/__init__.py b/src/django_idom/__init__.py
index fcb25a18..96d8df76 100644
--- a/src/django_idom/__init__.py
+++ b/src/django_idom/__init__.py
@@ -1,7 +1,7 @@
-from . import components, hooks, decorators
+from . import components, hooks, utils
from .websocket.consumer import IdomWebsocket
from .websocket.paths import IDOM_WEBSOCKET_PATH
__version__ = "1.1.0"
-__all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket", "hooks", "components", "decorators"]
+__all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket", "hooks", "components", "utils"]
diff --git a/src/django_idom/config.py b/src/django_idom/config.py
index 47f19455..17c0bdb7 100644
--- a/src/django_idom/config.py
+++ b/src/django_idom/config.py
@@ -4,11 +4,11 @@
from django.core.cache import DEFAULT_CACHE_ALIAS, caches
from idom.core.types import ComponentConstructor
-from django_idom.types import ViewToComponentIframe
+from django_idom.types import ViewComponentIframe
IDOM_REGISTERED_COMPONENTS: Dict[str, ComponentConstructor] = {}
-IDOM_REGISTERED_IFRAMES: Dict[str, ViewToComponentIframe] = {}
+IDOM_VIEW_COMPONENT_IFRAMES: Dict[str, ViewComponentIframe] = {}
IDOM_WEBSOCKET_URL = getattr(settings, "IDOM_WEBSOCKET_URL", "idom/")
IDOM_WS_MAX_RECONNECT_TIMEOUT = getattr(
diff --git a/src/django_idom/decorators.py b/src/django_idom/decorators.py
deleted file mode 100644
index 61d9f469..00000000
--- a/src/django_idom/decorators.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from inspect import isclass, iscoroutinefunction
-from typing import Callable
-
-from asgiref.sync import async_to_sync
-from django.urls import reverse
-from idom import component, html, utils
-from idom.core.component import Component
-
-from django_idom.config import IDOM_REGISTERED_IFRAMES
-from django_idom.types import ViewToComponentIframe
-
-
-def view_to_component(
- middleware: list[Callable | str], compatibility: bool = False, *args, **kwargs
-) -> Component | object:
- """Converts a Django view to an IDOM component.
-
- Args:
- middleware: The list of middleware to use when rendering the component.
- compatibility: If True, the component will be rendered in an iframe.
- *args: The positional arguments to pass to the view.
-
- Keyword Args:
- **kwargs: The keyword arguments to pass to the view.
- """
-
- def decorator(view):
-
- dotted_path = f"{view.__module__}.{view.__name__}".replace("<", "").replace(
- ">", ""
- )
-
- @component
- def new_component():
- if compatibility:
- return html.iframe(
- {
- "src": reverse("idom:view_to_component", args=[dotted_path]),
- "loading": "lazy",
- }
- )
-
- # TODO: Apply middleware using some helper function
- if isclass(view):
- rendered_view = view.as_view()(*args, **kwargs)
- elif iscoroutinefunction(view):
- rendered_view = async_to_sync(view)(*args, **kwargs)
- else:
- rendered_view = view(*args, **kwargs)
-
- return html._(utils.html_to_vdom(rendered_view))
-
- IDOM_REGISTERED_IFRAMES[dotted_path] = ViewToComponentIframe(
- middleware, view, new_component, args, kwargs
- )
-
- return new_component
-
- return decorator
diff --git a/src/django_idom/http/views.py b/src/django_idom/http/views.py
index 9623cb2f..5542052a 100644
--- a/src/django_idom/http/views.py
+++ b/src/django_idom/http/views.py
@@ -7,7 +7,7 @@
from django.http import HttpRequest, HttpResponse
from idom.config import IDOM_WED_MODULES_DIR
-from django_idom.config import IDOM_CACHE, IDOM_REGISTERED_IFRAMES
+from django_idom.config import IDOM_CACHE, IDOM_VIEW_COMPONENT_IFRAMES
async def web_modules_file(request: HttpRequest, file: str) -> HttpResponse:
@@ -36,20 +36,22 @@ async def web_modules_file(request: HttpRequest, file: str) -> HttpResponse:
return response
-async def view_to_component_iframe(view_path: str) -> HttpResponse:
+async def view_to_component_iframe(
+ request: HttpRequest, view_path: str
+) -> HttpResponse:
"""Returns a Django view that was registered by view_to_component.
This is used by `view_to_component` to render the view within an iframe."""
# Get the view from IDOM_REGISTERED_IFRAMES
- iframe = IDOM_REGISTERED_IFRAMES.get(view_path)
+ iframe = IDOM_VIEW_COMPONENT_IFRAMES.get(view_path)
if not iframe:
raise ValueError(f"No view registered for component {view_path}.")
# Render the view
# TODO: Apply middleware using some helper function~
if isclass(iframe):
- return await database_sync_to_async(iframe.view.as_view())()
+ return await database_sync_to_async(iframe.view.as_view())(request)
if iscoroutinefunction(iframe):
- return await iframe.view()
+ return await iframe.view(request)
- return await database_sync_to_async(iframe.view)()
+ return await database_sync_to_async(iframe.view)(request)
diff --git a/src/django_idom/types.py b/src/django_idom/types.py
index 52efa461..407af065 100644
--- a/src/django_idom/types.py
+++ b/src/django_idom/types.py
@@ -6,8 +6,8 @@
@dataclass
-class ViewToComponentIframe:
- middleware: list[Callable | str]
+class ViewComponentIframe:
+ middleware: list[Callable | str] | None
view: View | Callable
component: Component | object
args: Tuple
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index 81783013..bd9b449a 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -4,18 +4,79 @@
import re
from fnmatch import fnmatch
from importlib import import_module
-from typing import Set
+from inspect import isclass, iscoroutinefunction
+from typing import Callable, Set
+from asgiref.sync import async_to_sync
from django.template import engines
+from django.urls import reverse
from django.utils.encoding import smart_str
+from idom import component, html, utils
-from django_idom.config import IDOM_REGISTERED_COMPONENTS
+from django_idom.config import IDOM_REGISTERED_COMPONENTS, IDOM_VIEW_COMPONENT_IFRAMES
+from django_idom.types import ViewComponentIframe
COMPONENT_REGEX = re.compile(r"{% *component +((\"[^\"']*\")|('[^\"']*'))(.*?)%}")
_logger = logging.getLogger(__name__)
+def view_to_component(
+ view: Callable,
+ middleware: list[Callable | str] | None = None,
+ compatibility: bool = False,
+ *args,
+ **kwargs,
+):
+ """Converts a Django view to an IDOM component.
+
+ Args:
+ middleware: The list of middleware to use when rendering the component.
+ compatibility: If True, the component will be rendered in an iframe.
+ This requires X_FRAME_OPTIONS = 'SAMEORIGIN' in settings.py.
+ *args: The positional arguments to pass to the view.
+
+ Keyword Args:
+ **kwargs: The keyword arguments to pass to the view.
+ """
+
+ dotted_path = f"{view.__module__}.{view.__name__}".replace("<", "").replace(">", "")
+
+ @component
+ def new_component():
+
+ # Use compatibility mode if requested
+ if compatibility:
+ return html.iframe(
+ {
+ "src": reverse("idom:view_to_component", args=[dotted_path]),
+ "loading": "lazy",
+ }
+ )
+
+ # TODO: Apply middleware using some helper function
+ if isclass(view):
+ print("class view")
+ rendered_view = view.as_view()(*args, **kwargs)
+ elif iscoroutinefunction(view):
+ print("async view")
+ rendered_view = async_to_sync(view)(*args, **kwargs)
+ else:
+ print("function view")
+ rendered_view = view(*args, **kwargs)
+
+ print("vdom")
+ return html._(utils.html_to_vdom(rendered_view))
+
+ # Register the component as an iFrame if using compatibility mode
+ if compatibility:
+ IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe(
+ middleware, view, new_component, args, kwargs
+ )
+
+ return new_component()
+
+
def _register_component(full_component_name: str) -> None:
if full_component_name in IDOM_REGISTERED_COMPONENTS:
return
diff --git a/tests/test_app/components.py b/tests/test_app/components.py
index 13939f8b..c39e30d2 100644
--- a/tests/test_app/components.py
+++ b/tests/test_app/components.py
@@ -2,6 +2,8 @@
import django_idom
+from . import views
+
@idom.component
def HelloWorld():
@@ -93,3 +95,30 @@ def StaticJS():
django_idom.components.DjangoJS("static-js-test.js"),
idom.html.hr(),
)
+
+
+@idom.component
+def ViewToComponent():
+ return django_idom.utils.view_to_component(views.view_to_component)
+
+
+@idom.component
+def ViewToComponentAsync():
+ return django_idom.utils.view_to_component(views.view_to_component_async)
+
+
+@idom.component
+def ViewToComponentClass():
+ return django_idom.utils.view_to_component(views.ViewToComponentClass)
+
+
+@idom.component
+def ViewToComponentCompat():
+ return django_idom.utils.view_to_component(
+ views.view_to_component_compat, compatibility=True
+ )
+
+
+@idom.component
+def ViewToComponentMiddleware():
+ return django_idom.utils.view_to_component(views.view_to_component_middleware)
diff --git a/tests/test_app/settings.py b/tests/test_app/settings.py
index fbacac81..5aa62076 100644
--- a/tests/test_app/settings.py
+++ b/tests/test_app/settings.py
@@ -27,6 +27,7 @@
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["*"]
+X_FRAME_OPTIONS = "SAMEORIGIN"
# Application definition
INSTALLED_APPS = [
diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html
index c597cdf9..965facc8 100644
--- a/tests/test_app/templates/base.html
+++ b/tests/test_app/templates/base.html
@@ -21,6 +21,11 @@ IDOM Test Page
{% component "test_app.components.UseLocation" %}
{% component "test_app.components.StaticCSS" %}
{% component "test_app.components.StaticJS" %}
+
+
+
+ {% component "test_app.components.ViewToComponentCompat" %}
+
diff --git a/tests/test_app/templates/view_to_component.html b/tests/test_app/templates/view_to_component.html
new file mode 100644
index 00000000..76ed053c
--- /dev/null
+++ b/tests/test_app/templates/view_to_component.html
@@ -0,0 +1,2 @@
+{{test_name}}: Success
+
\ No newline at end of file
diff --git a/tests/test_app/views.py b/tests/test_app/views.py
index 11874908..2cc72456 100644
--- a/tests/test_app/views.py
+++ b/tests/test_app/views.py
@@ -1,6 +1,33 @@
from django.shortcuts import render
+from django.views.generic import TemplateView
def base_template(request):
context = {}
return render(request, "base.html", context)
+
+
+def view_to_component(request):
+ return render(request, "view_to_component.html", {"test_name": "view_to_component"})
+
+
+async def view_to_component_async(request):
+ return render(
+ request, "view_to_component.html", {"test_name": "view_to_component_async"}
+ )
+
+
+class ViewToComponentClass(TemplateView):
+ template_name = "view_to_component.html"
+
+
+def view_to_component_compat(request):
+ return render(
+ request, "view_to_component.html", {"test_name": "view_to_component_compat"}
+ )
+
+
+def view_to_component_middleware(request):
+ return render(
+ request, "view_to_component.html", {"test_name": "view_to_component_middleware"}
+ )
From e53c15df497d8fdd6eca9f3254e99d9f797d8b12 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 15:57:57 -0700
Subject: [PATCH 030/110] functional standard view to component
---
src/django_idom/utils.py | 9 +++++----
tests/test_app/templates/base.html | 2 +-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index bd9b449a..530a42b4 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -8,6 +8,7 @@
from typing import Callable, Set
from asgiref.sync import async_to_sync
+from django.http import HttpRequest
from django.template import engines
from django.urls import reverse
from django.utils.encoding import smart_str
@@ -57,16 +58,16 @@ def new_component():
# TODO: Apply middleware using some helper function
if isclass(view):
print("class view")
- rendered_view = view.as_view()(*args, **kwargs)
+ rendered_view = view.as_view()(HttpRequest(), *args, **kwargs)
elif iscoroutinefunction(view):
print("async view")
- rendered_view = async_to_sync(view)(*args, **kwargs)
+ rendered_view = async_to_sync(view)(HttpRequest(), *args, **kwargs)
else:
print("function view")
- rendered_view = view(*args, **kwargs)
+ rendered_view = view(HttpRequest(), *args, **kwargs)
print("vdom")
- return html._(utils.html_to_vdom(rendered_view))
+ return html._(utils.html_to_vdom(rendered_view.content.decode("utf-8")))
# Register the component as an iFrame if using compatibility mode
if compatibility:
diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html
index 965facc8..5b530046 100644
--- a/tests/test_app/templates/base.html
+++ b/tests/test_app/templates/base.html
@@ -21,7 +21,7 @@ IDOM Test Page
{% component "test_app.components.UseLocation" %}
{% component "test_app.components.StaticCSS" %}
{% component "test_app.components.StaticJS" %}
-
+ {% component "test_app.components.ViewToComponent" %}
{% component "test_app.components.ViewToComponentCompat" %}
From 86318e50a655fb40bc403e83997a387c580ddee5 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 17:07:04 -0700
Subject: [PATCH 031/110] class view to component
---
src/django_idom/utils.py | 10 ++++------
tests/test_app/components.py | 4 ++--
tests/test_app/templates/base.html | 4 ++--
tests/test_app/views.py | 9 +++++++--
4 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index 530a42b4..a6c16da5 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -45,7 +45,6 @@ def view_to_component(
@component
def new_component():
-
# Use compatibility mode if requested
if compatibility:
return html.iframe(
@@ -57,16 +56,15 @@ def new_component():
# TODO: Apply middleware using some helper function
if isclass(view):
- print("class view")
- rendered_view = view.as_view()(HttpRequest(), *args, **kwargs)
+ request = HttpRequest()
+ request.method = "GET"
+ rendered_view = view.as_view()(request, *args, **kwargs)
+ rendered_view.render()
elif iscoroutinefunction(view):
- print("async view")
rendered_view = async_to_sync(view)(HttpRequest(), *args, **kwargs)
else:
- print("function view")
rendered_view = view(HttpRequest(), *args, **kwargs)
- print("vdom")
return html._(utils.html_to_vdom(rendered_view.content.decode("utf-8")))
# Register the component as an iFrame if using compatibility mode
diff --git a/tests/test_app/components.py b/tests/test_app/components.py
index c39e30d2..a06be920 100644
--- a/tests/test_app/components.py
+++ b/tests/test_app/components.py
@@ -113,9 +113,9 @@ def ViewToComponentClass():
@idom.component
-def ViewToComponentCompat():
+def ViewToComponentCompatibility():
return django_idom.utils.view_to_component(
- views.view_to_component_compat, compatibility=True
+ views.view_to_component_compatibility, compatibility=True
)
diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html
index 5b530046..2076f2d6 100644
--- a/tests/test_app/templates/base.html
+++ b/tests/test_app/templates/base.html
@@ -23,8 +23,8 @@ IDOM Test Page
{% component "test_app.components.StaticJS" %}
{% component "test_app.components.ViewToComponent" %}
-
- {% component "test_app.components.ViewToComponentCompat" %}
+ {% component "test_app.components.ViewToComponentClass" %}
+ {% component "test_app.components.ViewToComponentCompatibility" %}
diff --git a/tests/test_app/views.py b/tests/test_app/views.py
index 2cc72456..40683a09 100644
--- a/tests/test_app/views.py
+++ b/tests/test_app/views.py
@@ -20,10 +20,15 @@ async def view_to_component_async(request):
class ViewToComponentClass(TemplateView):
template_name = "view_to_component.html"
+ def get_context_data(self, **kwargs):
+ return {"test_name": "view_to_component_class"}
-def view_to_component_compat(request):
+
+def view_to_component_compatibility(request):
return render(
- request, "view_to_component.html", {"test_name": "view_to_component_compat"}
+ request,
+ "view_to_component.html",
+ {"test_name": "view_to_component_compatibility"},
)
From 1e26dfad9d88fe6dcdeb1e2e9907d5ab92025591 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 17:08:32 -0700
Subject: [PATCH 032/110] fix HR on JS test
---
tests/test_app/components.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/tests/test_app/components.py b/tests/test_app/components.py
index 13939f8b..54fc3dd8 100644
--- a/tests/test_app/components.py
+++ b/tests/test_app/components.py
@@ -87,9 +87,11 @@ def StaticCSS():
@idom.component
def StaticJS():
success = False
- return idom.html.div(
- {"id": "static-js", "data-success": success},
- f"StaticJS: {success}",
- django_idom.components.DjangoJS("static-js-test.js"),
+ return idom.html._(
+ idom.html.div(
+ {"id": "static-js", "data-success": success},
+ f"StaticJS: {success}",
+ django_idom.components.DjangoJS("static-js-test.js"),
+ ),
idom.html.hr(),
)
From 823600e3b51024dfc40cf2e9cc42a23f8ea42938 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 17:15:37 -0700
Subject: [PATCH 033/110] add ID to compat
---
tests/test_app/components.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/tests/test_app/components.py b/tests/test_app/components.py
index 74b8090b..0e362d5d 100644
--- a/tests/test_app/components.py
+++ b/tests/test_app/components.py
@@ -116,8 +116,11 @@ def ViewToComponentClass():
@idom.component
def ViewToComponentCompatibility():
- return django_idom.utils.view_to_component(
- views.view_to_component_compatibility, compatibility=True
+ return idom.html.div(
+ {"id": "view_to_component_compatibility"},
+ django_idom.utils.view_to_component(
+ views.view_to_component_compatibility, compatibility=True
+ ),
)
From fa8efd310edb931d292f03daa0d79a62b0f1a364 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 17:15:46 -0700
Subject: [PATCH 034/110] type hinting cleanup
---
src/django_idom/utils.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index a6c16da5..de077423 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -13,6 +13,7 @@
from django.urls import reverse
from django.utils.encoding import smart_str
from idom import component, html, utils
+from idom.types import ComponentType
from django_idom.config import IDOM_REGISTERED_COMPONENTS, IDOM_VIEW_COMPONENT_IFRAMES
from django_idom.types import ViewComponentIframe
@@ -28,7 +29,7 @@ def view_to_component(
compatibility: bool = False,
*args,
**kwargs,
-):
+) -> ComponentType:
"""Converts a Django view to an IDOM component.
Args:
From 1cdc5c2abe30afd737fe0035bba5eb06e44e61ab Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 17:56:41 -0700
Subject: [PATCH 035/110] ViewToComponentAsync
---
src/django_idom/utils.py | 24 +++++++++++++++++++-----
tests/test_app/templates/base.html | 2 +-
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index de077423..64be1f56 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -7,12 +7,11 @@
from inspect import isclass, iscoroutinefunction
from typing import Callable, Set
-from asgiref.sync import async_to_sync
from django.http import HttpRequest
from django.template import engines
from django.urls import reverse
from django.utils.encoding import smart_str
-from idom import component, html, utils
+from idom import component, hooks, html, utils
from idom.types import ComponentType
from django_idom.config import IDOM_REGISTERED_COMPONENTS, IDOM_VIEW_COMPONENT_IFRAMES
@@ -46,7 +45,20 @@ def view_to_component(
@component
def new_component():
- # Use compatibility mode if requested
+ # Hack for getting around some of Django's Async/Sync protections
+ async_view = False
+ async_render, set_async_render = hooks.use_state(None)
+ if async_render:
+ return html._(utils.html_to_vdom(async_render.content.decode("utf-8")))
+
+ async def async_renderer():
+ if async_view is True and not async_render:
+ rendered_view = await view(HttpRequest(), *args, **kwargs)
+ set_async_render(rendered_view)
+
+ hooks.use_effect(async_renderer, dependencies=[async_view])
+
+ # Generate an iFrame component for compatibility, if requested
if compatibility:
return html.iframe(
{
@@ -55,6 +67,7 @@ def new_component():
}
)
+ # Convert the view HTML to VDOM
# TODO: Apply middleware using some helper function
if isclass(view):
request = HttpRequest()
@@ -62,13 +75,14 @@ def new_component():
rendered_view = view.as_view()(request, *args, **kwargs)
rendered_view.render()
elif iscoroutinefunction(view):
- rendered_view = async_to_sync(view)(HttpRequest(), *args, **kwargs)
+ async_view = True
+ return None
else:
rendered_view = view(HttpRequest(), *args, **kwargs)
return html._(utils.html_to_vdom(rendered_view.content.decode("utf-8")))
- # Register the component as an iFrame if using compatibility mode
+ # Register the iFrame component for compatibility, if requested
if compatibility:
IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe(
middleware, view, new_component, args, kwargs
diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html
index 2076f2d6..22038c5b 100644
--- a/tests/test_app/templates/base.html
+++ b/tests/test_app/templates/base.html
@@ -22,7 +22,7 @@ IDOM Test Page
{% component "test_app.components.StaticCSS" %}
{% component "test_app.components.StaticJS" %}
{% component "test_app.components.ViewToComponent" %}
-
+ {% component "test_app.components.ViewToComponentAsync" %}
{% component "test_app.components.ViewToComponentClass" %}
{% component "test_app.components.ViewToComponentCompatibility" %}
From 643940ef2c63d2bd1c28bd98e2ce6ee812e1c9cd Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 20:20:54 -0700
Subject: [PATCH 036/110] ViewToComponentMiddleware
---
src/django_idom/utils.py | 64 +++++++++++++++++++++++-------
tests/test_app/components.py | 17 +++++++-
tests/test_app/templates/base.html | 3 +-
tests/test_app/views.py | 8 +++-
4 files changed, 75 insertions(+), 17 deletions(-)
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index 64be1f56..66bdcbb9 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -26,6 +26,7 @@ def view_to_component(
view: Callable,
middleware: list[Callable | str] | None = None,
compatibility: bool = False,
+ request: HttpRequest | None = None,
*args,
**kwargs,
) -> ComponentType:
@@ -35,6 +36,7 @@ def view_to_component(
middleware: The list of middleware to use when rendering the component.
compatibility: If True, the component will be rendered in an iframe.
This requires X_FRAME_OPTIONS = 'SAMEORIGIN' in settings.py.
+ request: Request object to provide to the view.
*args: The positional arguments to pass to the view.
Keyword Args:
@@ -45,7 +47,14 @@ def view_to_component(
@component
def new_component():
+ # Create a synthetic request object.
+ request_obj = request
+ if not request:
+ request_obj = HttpRequest()
+ request_obj.method = "GET"
+
# Hack for getting around some of Django's Async/Sync protections
+ # Without this, we wouldn't be able to render async views within components
async_view = False
async_render, set_async_render = hooks.use_state(None)
if async_render:
@@ -53,12 +62,14 @@ def new_component():
async def async_renderer():
if async_view is True and not async_render:
- rendered_view = await view(HttpRequest(), *args, **kwargs)
+ rendered_view = await _view_middleware(middleware, view)(
+ request_obj, *args, **kwargs
+ )
set_async_render(rendered_view)
hooks.use_effect(async_renderer, dependencies=[async_view])
- # Generate an iFrame component for compatibility, if requested
+ # Generate an iframe component for compatibility, if requested
if compatibility:
return html.iframe(
{
@@ -70,19 +81,23 @@ async def async_renderer():
# Convert the view HTML to VDOM
# TODO: Apply middleware using some helper function
if isclass(view):
- request = HttpRequest()
- request.method = "GET"
- rendered_view = view.as_view()(request, *args, **kwargs)
+ rendered_view = _view_middleware(middleware, view.as_view())(
+ request_obj, *args, **kwargs
+ )
rendered_view.render()
elif iscoroutinefunction(view):
+ # Queue the view to be rendered within an UseEffect hook due to
+ # async/sync limitations
async_view = True
return None
else:
- rendered_view = view(HttpRequest(), *args, **kwargs)
+ rendered_view = _view_middleware(middleware, view)(
+ request_obj, *args, **kwargs
+ )
return html._(utils.html_to_vdom(rendered_view.content.decode("utf-8")))
- # Register the iFrame component for compatibility, if requested
+ # Register the iframe component for compatibility, if requested
if compatibility:
IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe(
middleware, view, new_component, args, kwargs
@@ -91,11 +106,27 @@ async def async_renderer():
return new_component()
-def _register_component(full_component_name: str) -> None:
- if full_component_name in IDOM_REGISTERED_COMPONENTS:
- return
+def _view_middleware(
+ middleware: list[Callable | str] | None, view: Callable
+) -> Callable:
+ """Applies middleware to a view."""
+ if not middleware:
+ return view
+
+ def _wrapper(*args, **kwargs):
+ new_view = view
+ for middleware_item in middleware:
+ if isinstance(middleware_item, str):
+ middleware_item = _import_dotted_path(middleware_item)
+ new_view = middleware_item(new_view)(*args, **kwargs)
+ return new_view
- module_name, component_name = full_component_name.rsplit(".", 1)
+ return _wrapper
+
+
+def _import_dotted_path(dotted_path: str) -> Callable:
+ """Imports a dotted path and returns the callable."""
+ module_name, component_name = dotted_path.rsplit(".", 1)
try:
module = import_module(module_name)
@@ -105,14 +136,19 @@ def _register_component(full_component_name: str) -> None:
) from error
try:
- component = getattr(module, component_name)
+ return getattr(module, component_name)
except AttributeError as error:
raise RuntimeError(
f"Module {module_name!r} has no component named {component_name!r}"
) from error
- IDOM_REGISTERED_COMPONENTS[full_component_name] = component
- _logger.debug("IDOM has registered component %s", full_component_name)
+
+def _register_component(dotted_path: str) -> None:
+ if dotted_path in IDOM_REGISTERED_COMPONENTS:
+ return
+
+ IDOM_REGISTERED_COMPONENTS[dotted_path] = _import_dotted_path(dotted_path)
+ _logger.debug("IDOM has registered component %s", dotted_path)
class ComponentPreloader:
diff --git a/tests/test_app/components.py b/tests/test_app/components.py
index 0e362d5d..b4b631ee 100644
--- a/tests/test_app/components.py
+++ b/tests/test_app/components.py
@@ -121,9 +121,24 @@ def ViewToComponentCompatibility():
django_idom.utils.view_to_component(
views.view_to_component_compatibility, compatibility=True
),
+ idom.html.hr(),
)
@idom.component
def ViewToComponentMiddleware():
- return django_idom.utils.view_to_component(views.view_to_component_middleware)
+ def str_replace_middleware(view):
+ def middleware(request, *args, **kwargs):
+ render = view(request, *args, **kwargs)
+ render.content = render.content.decode("utf-8").replace("_not_working", "")
+ return render
+ return middleware
+
+ return django_idom.utils.view_to_component(
+ views.view_to_component_middleware, middleware=[str_replace_middleware]
+ )
+
+
+@idom.component
+def ViewToComponentScripts():
+ return django_idom.utils.view_to_component(views.view_to_component_scripts)
diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html
index 22038c5b..6a6d2d75 100644
--- a/tests/test_app/templates/base.html
+++ b/tests/test_app/templates/base.html
@@ -25,7 +25,8 @@ IDOM Test Page
{% component "test_app.components.ViewToComponentAsync" %}
{% component "test_app.components.ViewToComponentClass" %}
{% component "test_app.components.ViewToComponentCompatibility" %}
-
+ {% component "test_app.components.ViewToComponentMiddleware" %}
+
diff --git a/tests/test_app/views.py b/tests/test_app/views.py
index 40683a09..be845f75 100644
--- a/tests/test_app/views.py
+++ b/tests/test_app/views.py
@@ -34,5 +34,11 @@ def view_to_component_compatibility(request):
def view_to_component_middleware(request):
return render(
- request, "view_to_component.html", {"test_name": "view_to_component_middleware"}
+ request, "view_to_component.html", {"test_name": "view_to_component_middleware_not_working"}
+ )
+
+
+def view_to_component_scripts(request):
+ return render(
+ request, "view_to_component.html", {"test_name": "view_to_component_scripts_not_working"}
)
From 683300887392274a162bfcd95a739a33711ef142 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 20:26:58 -0700
Subject: [PATCH 037/110] fix flake8 warning
---
src/django_idom/utils.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index 66bdcbb9..d0d0d696 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -7,11 +7,12 @@
from inspect import isclass, iscoroutinefunction
from typing import Callable, Set
+import idom
from django.http import HttpRequest
from django.template import engines
from django.urls import reverse
from django.utils.encoding import smart_str
-from idom import component, hooks, html, utils
+from idom import hooks, html, utils
from idom.types import ComponentType
from django_idom.config import IDOM_REGISTERED_COMPONENTS, IDOM_VIEW_COMPONENT_IFRAMES
@@ -45,7 +46,7 @@ def view_to_component(
dotted_path = f"{view.__module__}.{view.__name__}".replace("<", "").replace(">", "")
- @component
+ @idom.component
def new_component():
# Create a synthetic request object.
request_obj = request
From 5371b24c62a6c60dd0c539a0a24b2b7b96a5b470 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 20:28:40 -0700
Subject: [PATCH 038/110] format tests folder
---
tests/test_app/components.py | 1 +
tests/test_app/views.py | 8 ++++++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/tests/test_app/components.py b/tests/test_app/components.py
index b4b631ee..db053d89 100644
--- a/tests/test_app/components.py
+++ b/tests/test_app/components.py
@@ -132,6 +132,7 @@ def middleware(request, *args, **kwargs):
render = view(request, *args, **kwargs)
render.content = render.content.decode("utf-8").replace("_not_working", "")
return render
+
return middleware
return django_idom.utils.view_to_component(
diff --git a/tests/test_app/views.py b/tests/test_app/views.py
index be845f75..13f807c3 100644
--- a/tests/test_app/views.py
+++ b/tests/test_app/views.py
@@ -34,11 +34,15 @@ def view_to_component_compatibility(request):
def view_to_component_middleware(request):
return render(
- request, "view_to_component.html", {"test_name": "view_to_component_middleware_not_working"}
+ request,
+ "view_to_component.html",
+ {"test_name": "view_to_component_middleware_not_working"},
)
def view_to_component_scripts(request):
return render(
- request, "view_to_component.html", {"test_name": "view_to_component_scripts_not_working"}
+ request,
+ "view_to_component.html",
+ {"test_name": "view_to_component_scripts_not_working"},
)
From a2cd686bcf9a9c768c898da32f4d4fbcd6d7c2b6 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 20:54:14 -0700
Subject: [PATCH 039/110] ViewToComponentScript
---
src/django_idom/utils.py | 2 +-
tests/test_app/components.py | 6 +++---
tests/test_app/templates/base.html | 2 +-
tests/test_app/templates/view_to_component.html | 4 ++--
tests/test_app/templates/view_to_component_script.html | 8 ++++++++
tests/test_app/views.py | 8 ++++----
6 files changed, 19 insertions(+), 11 deletions(-)
create mode 100644 tests/test_app/templates/view_to_component_script.html
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index d0d0d696..29165640 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -96,7 +96,7 @@ async def async_renderer():
request_obj, *args, **kwargs
)
- return html._(utils.html_to_vdom(rendered_view.content.decode("utf-8")))
+ return html._(utils.html_to_vdom(rendered_view.content.decode("utf-8").strip()))
# Register the iframe component for compatibility, if requested
if compatibility:
diff --git a/tests/test_app/components.py b/tests/test_app/components.py
index db053d89..7a78f69c 100644
--- a/tests/test_app/components.py
+++ b/tests/test_app/components.py
@@ -130,7 +130,7 @@ def ViewToComponentMiddleware():
def str_replace_middleware(view):
def middleware(request, *args, **kwargs):
render = view(request, *args, **kwargs)
- render.content = render.content.decode("utf-8").replace("_not_working", "")
+ render.content = render.content.decode("utf-8").replace("Fail", "Success")
return render
return middleware
@@ -141,5 +141,5 @@ def middleware(request, *args, **kwargs):
@idom.component
-def ViewToComponentScripts():
- return django_idom.utils.view_to_component(views.view_to_component_scripts)
+def ViewToComponentScript():
+ return django_idom.utils.view_to_component(views.view_to_component_script)
diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html
index 6a6d2d75..63f00908 100644
--- a/tests/test_app/templates/base.html
+++ b/tests/test_app/templates/base.html
@@ -26,7 +26,7 @@ IDOM Test Page
{% component "test_app.components.ViewToComponentClass" %}
{% component "test_app.components.ViewToComponentCompatibility" %}
{% component "test_app.components.ViewToComponentMiddleware" %}
-
+ {% component "test_app.components.ViewToComponentScript" %}
diff --git a/tests/test_app/templates/view_to_component.html b/tests/test_app/templates/view_to_component.html
index 76ed053c..7ed7d406 100644
--- a/tests/test_app/templates/view_to_component.html
+++ b/tests/test_app/templates/view_to_component.html
@@ -1,2 +1,2 @@
-{{test_name}}: Success
-
\ No newline at end of file
+{{ test_name}}: {% firstof status "Success" %}
+
{% block bottom %}{% endblock %}
\ No newline at end of file
diff --git a/tests/test_app/templates/view_to_component_script.html b/tests/test_app/templates/view_to_component_script.html
new file mode 100644
index 00000000..f63a0a56
--- /dev/null
+++ b/tests/test_app/templates/view_to_component_script.html
@@ -0,0 +1,8 @@
+{% extends "view_to_component.html" %}
+{% block bottom %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/tests/test_app/views.py b/tests/test_app/views.py
index 13f807c3..edea425a 100644
--- a/tests/test_app/views.py
+++ b/tests/test_app/views.py
@@ -36,13 +36,13 @@ def view_to_component_middleware(request):
return render(
request,
"view_to_component.html",
- {"test_name": "view_to_component_middleware_not_working"},
+ {"test_name": "view_to_component_middleware", "status": "Fail"},
)
-def view_to_component_scripts(request):
+def view_to_component_script(request):
return render(
request,
- "view_to_component.html",
- {"test_name": "view_to_component_scripts_not_working"},
+ "view_to_component_script.html",
+ {"test_name": "view_to_component_script", "status": "Fail"},
)
From 1dda52d01022cca47da25610c2cf97a45c6a34d3 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 21:00:53 -0700
Subject: [PATCH 040/110] swap pipe operator with union
---
src/django_idom/types.py | 8 ++++----
src/django_idom/utils.py | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/django_idom/types.py b/src/django_idom/types.py
index 407af065..673ed207 100644
--- a/src/django_idom/types.py
+++ b/src/django_idom/types.py
@@ -1,5 +1,5 @@
from dataclasses import dataclass
-from typing import Callable, Tuple
+from typing import Callable, Tuple, Union
from django.views.generic import View
from idom.core.component import Component
@@ -7,8 +7,8 @@
@dataclass
class ViewComponentIframe:
- middleware: list[Callable | str] | None
- view: View | Callable
- component: Component | object
+ middleware: Union[list[Union[Callable, str]], None]
+ view: Union[View, Callable]
+ component: Union[Component, object]
args: Tuple
kwargs: dict
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index 29165640..34651d10 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -5,7 +5,7 @@
from fnmatch import fnmatch
from importlib import import_module
from inspect import isclass, iscoroutinefunction
-from typing import Callable, Set
+from typing import Callable, Set, Union
import idom
from django.http import HttpRequest
@@ -25,9 +25,9 @@
def view_to_component(
view: Callable,
- middleware: list[Callable | str] | None = None,
+ middleware: Union[list[Union[Callable, str]], None] = None,
compatibility: bool = False,
- request: HttpRequest | None = None,
+ request: Union[HttpRequest, None] = None,
*args,
**kwargs,
) -> ComponentType:
@@ -108,7 +108,7 @@ async def async_renderer():
def _view_middleware(
- middleware: list[Callable | str] | None, view: Callable
+ middleware: Union[list[Union[Callable, str]], None], view: Callable
) -> Callable:
"""Applies middleware to a view."""
if not middleware:
From ada489c425b08c7aa8e300870c2ffcb566574b58 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 21:05:26 -0700
Subject: [PATCH 041/110] swap list with typing.List
---
src/django_idom/types.py | 4 ++--
src/django_idom/utils.py | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/django_idom/types.py b/src/django_idom/types.py
index 673ed207..f1792d15 100644
--- a/src/django_idom/types.py
+++ b/src/django_idom/types.py
@@ -1,5 +1,5 @@
from dataclasses import dataclass
-from typing import Callable, Tuple, Union
+from typing import Callable, List, Tuple, Union
from django.views.generic import View
from idom.core.component import Component
@@ -7,7 +7,7 @@
@dataclass
class ViewComponentIframe:
- middleware: Union[list[Union[Callable, str]], None]
+ middleware: Union[List[Union[Callable, str]], None]
view: Union[View, Callable]
component: Union[Component, object]
args: Tuple
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index 34651d10..089b7ca4 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -5,7 +5,7 @@
from fnmatch import fnmatch
from importlib import import_module
from inspect import isclass, iscoroutinefunction
-from typing import Callable, Set, Union
+from typing import Callable, List, Set, Union
import idom
from django.http import HttpRequest
@@ -25,7 +25,7 @@
def view_to_component(
view: Callable,
- middleware: Union[list[Union[Callable, str]], None] = None,
+ middleware: Union[List[Union[Callable, str]], None] = None,
compatibility: bool = False,
request: Union[HttpRequest, None] = None,
*args,
@@ -108,7 +108,7 @@ async def async_renderer():
def _view_middleware(
- middleware: Union[list[Union[Callable, str]], None], view: Callable
+ middleware: Union[List[Union[Callable, str]], None], view: Callable
) -> Callable:
"""Applies middleware to a view."""
if not middleware:
From 3aca1377d35ad1170d804694221b56dd98846dc1 Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 22:00:11 -0700
Subject: [PATCH 042/110] minor refactoring
---
src/django_idom/utils.py | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index 089b7ca4..a7783721 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -54,12 +54,21 @@ def new_component():
request_obj = HttpRequest()
request_obj.method = "GET"
+ # Generate an iframe if compatibility mode is enabled.
+ if compatibility:
+ return html.iframe(
+ {
+ "src": reverse("idom:view_to_component", args=[dotted_path]),
+ "loading": "lazy",
+ }
+ )
+
# Hack for getting around some of Django's Async/Sync protections
# Without this, we wouldn't be able to render async views within components
async_view = False
async_render, set_async_render = hooks.use_state(None)
if async_render:
- return html._(utils.html_to_vdom(async_render.content.decode("utf-8")))
+ return html._(utils.html_to_vdom(async_render.content.decode("utf-8").strip()))
async def async_renderer():
if async_view is True and not async_render:
@@ -70,15 +79,6 @@ async def async_renderer():
hooks.use_effect(async_renderer, dependencies=[async_view])
- # Generate an iframe component for compatibility, if requested
- if compatibility:
- return html.iframe(
- {
- "src": reverse("idom:view_to_component", args=[dotted_path]),
- "loading": "lazy",
- }
- )
-
# Convert the view HTML to VDOM
# TODO: Apply middleware using some helper function
if isclass(view):
@@ -98,7 +98,7 @@ async def async_renderer():
return html._(utils.html_to_vdom(rendered_view.content.decode("utf-8").strip()))
- # Register the iframe component for compatibility, if requested
+ # Register an iframe if compatibility mode is enabled
if compatibility:
IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe(
middleware, view, new_component, args, kwargs
From df6202bc2995283052642b5ec7ffdc971723c93e Mon Sep 17 00:00:00 2001
From: Archmonger <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 28 Jun 2022 22:11:38 -0700
Subject: [PATCH 043/110] Add todos
---
src/django_idom/http/views.py | 1 -
src/django_idom/utils.py | 1 -
tests/test_app/templates/base.html | 6 +++++-
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/django_idom/http/views.py b/src/django_idom/http/views.py
index 5542052a..223fc75a 100644
--- a/src/django_idom/http/views.py
+++ b/src/django_idom/http/views.py
@@ -47,7 +47,6 @@ async def view_to_component_iframe(
raise ValueError(f"No view registered for component {view_path}.")
# Render the view
- # TODO: Apply middleware using some helper function~
if isclass(iframe):
return await database_sync_to_async(iframe.view.as_view())(request)
diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py
index a7783721..91996dde 100644
--- a/src/django_idom/utils.py
+++ b/src/django_idom/utils.py
@@ -80,7 +80,6 @@ async def async_renderer():
hooks.use_effect(async_renderer, dependencies=[async_view])
# Convert the view HTML to VDOM
- # TODO: Apply middleware using some helper function
if isclass(view):
rendered_view = _view_middleware(middleware, view.as_view())(
request_obj, *args, **kwargs
diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html
index 63f00908..703aeffd 100644
--- a/tests/test_app/templates/base.html
+++ b/tests/test_app/templates/base.html
@@ -22,11 +22,15 @@ IDOM Test Page
{% component "test_app.components.StaticCSS" %}
{% component "test_app.components.StaticJS" %}
{% component "test_app.components.ViewToComponent" %}
+ {% component "test_app.components.ViewToComponentMiddleware" %}
{% component "test_app.components.ViewToComponentAsync" %}
+
{% component "test_app.components.ViewToComponentClass" %}
+
{% component "test_app.components.ViewToComponentCompatibility" %}
- {% component "test_app.components.ViewToComponentMiddleware" %}
+
{% component "test_app.components.ViewToComponentScript" %}
+