Skip to content

Commit af6601d

Browse files
committed
load components using template names
1 parent 937244c commit af6601d

File tree

8 files changed

+46
-106
lines changed

8 files changed

+46
-106
lines changed

README.md

+9-40
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ your_app/
4545
├── urls.py
4646
└── sub_app/
4747
├── __init__.py
48-
├── components.py
4948
├── idom.py
5049
├── templates/
5150
│ └── your-template.html
@@ -58,7 +57,7 @@ To start, we'll need to use [`channels`](https://channels.readthedocs.io/en/stab
5857
create a `ProtocolTypeRouter` that will become the top of our ASGI application stack.
5958
Under the `"websocket"` protocol, we'll then add a path for IDOM's websocket consumer
6059
using `idom_websocket_path`. If you wish to change the route where this
61-
websocket is served from see the available [settings](#settings.py).
60+
websocket is served from, see the available [settings](#settings.py).
6261

6362
```python
6463

@@ -104,15 +103,13 @@ You may configure additional options as well:
104103
```python
105104
# the base URL for all IDOM-releated resources
106105
IDOM_BASE_URL: str = "_idom/"
107-
108-
# ignore these INSTALLED_APPS during component collection
109-
IDOM_IGNORE_INSTALLED_APPS: list[str] = ["some_app", "some_other_app"]
110106
```
111107

112108
## `urls.py`
113109

114110
You'll need to include IDOM's static web modules path using `idom_web_modules_path`.
115-
Similarly to the `idom_websocket_path()`, these resources will be used globally.
111+
Similarly to the `idom_websocket_path()`. If you wish to change the route where this
112+
websocket is served from, see the available [settings](#settings.py).
116113

117114
```python
118115
from django_idom import idom_web_modules_path
@@ -128,54 +125,26 @@ urlpatterns = [
128125
This is where, by a convention similar to that of
129126
[`views.py`](https://docs.djangoproject.com/en/3.2/topics/http/views/), you'll define
130127
your [IDOM](https://github.com/idom-team/idom) components. Ultimately though, you should
131-
feel free to organize your component modules you wish.
128+
feel free to organize your component modules you wish. The components created here will
129+
ultimately be referenced by name in `your-template.html`. `your-template.html`.
132130

133131
```python
134132
import idom
135133

136134
@idom.component
137135
def Hello(name): # component names are camelcase by convention
138-
return idom.html.h1(f"Hello {name}!")
139-
```
140-
141-
## `sub_app/idom.py`
142-
143-
This file is automatically discovered by `django-idom` when scanning the list of
144-
[`INSTALLED_APPS`](https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-INSTALLED_APPS).
145-
All apps that export components will contain this module.
146-
147-
Inside this module must be a `components` list that is imported from
148-
[`components.py`](#sub_appcomponents.py):
149-
150-
```python
151-
from .components import Hello
152-
153-
components = [
154-
Hello,
155-
...
156-
]
157-
```
158-
159-
You may alternately reference the components with strings for the purpose of renaming:
160-
161-
```python
162-
from .components import Hello as SomeOtherName
163-
164-
components = [
165-
"SomeOtherName",
166-
...
167-
]
136+
return Header(f"Hello {name}!")
168137
```
169138

170139
## `sub_app/templates/your-template.html`
171140

172141
In your templates, you may inject a view of an IDOM component into your templated HTML
173142
by using the `idom_view` template tag. This tag which requires the name of a component
174-
to render (of the form `app_name.ComponentName`) and keyword arguments you'd like to
143+
to render (of the form `module_name.ComponentName`) and keyword arguments you'd like to
175144
pass it from the template.
176145

177146
```python
178-
idom_view app_name.ComponentName param_1="something" param_2="something-else"
147+
idom_view module_name.ComponentName param_1="something" param_2="something-else"
179148
```
180149

181150
In context this will look a bit like the following...
@@ -189,7 +158,7 @@ In context this will look a bit like the following...
189158
<html>
190159
<body>
191160
...
192-
{% idom_view "your_app.sub_app.Hello" name="World" %}
161+
{% idom_view "your_app.sub_app.components.Hello" name="World" %}
193162
</body>
194163
</html>
195164
```

src/django_idom/__init__.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from .components import register_component
21
from .paths import idom_web_modules_path, idom_websocket_path
32

43

54
__version__ = "0.0.1"
6-
__all__ = ["idom_websocket_path", "idom_web_modules_path", "register_component"]
5+
__all__ = ["idom_websocket_path", "idom_web_modules_path"]

src/django_idom/components.py

-48
This file was deleted.

src/django_idom/config.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66

77
IDOM_REGISTERED_COMPONENTS: Dict[str, ComponentConstructor] = {}
8+
IDOM_IGNORE_INSTALLED_APPS = set(getattr(settings, "IDOM_IGNORE_INSTALLED_APPS", []))
89

910
IDOM_BASE_URL = getattr(settings, "IDOM_BASE_URL", "_idom/")
1011
IDOM_WEBSOCKET_URL = IDOM_BASE_URL + "websocket/"

src/django_idom/templatetags/idom.py

+26-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import json
2+
import sys
3+
from importlib import import_module
24
from urllib.parse import urlencode
35
from uuid import uuid4
46

@@ -16,9 +18,7 @@
1618

1719
@register.inclusion_tag("idom/view.html")
1820
def idom_view(_component_id_, **kwargs):
19-
if _component_id_ not in IDOM_REGISTERED_COMPONENTS:
20-
print(list(IDOM_REGISTERED_COMPONENTS))
21-
raise ValueError(f"No component {_component_id_!r} exists")
21+
_register_component(_component_id_)
2222

2323
json_kwargs = json.dumps(kwargs, separators=(",", ":"))
2424

@@ -29,3 +29,26 @@ def idom_view(_component_id_, **kwargs):
2929
"idom_view_id": _component_id_,
3030
"idom_view_params": urlencode({"kwargs": json_kwargs}),
3131
}
32+
33+
34+
def _register_component(full_component_name: str) -> None:
35+
module_name, component_name = full_component_name.rsplit(".", 1)
36+
37+
if module_name in sys.modules:
38+
module = sys.modules[module_name]
39+
else:
40+
try:
41+
module = import_module(module_name)
42+
except ImportError as error:
43+
raise RuntimeError(
44+
f"Failed to import {module_name!r} while loading {component_name!r}"
45+
) from error
46+
47+
try:
48+
component = getattr(module, component_name)
49+
except AttributeError as error:
50+
raise RuntimeError(
51+
f"Module {module_name!r} has no component named {component_name!r}"
52+
) from error
53+
54+
IDOM_REGISTERED_COMPONENTS[full_component_name] = component

tests/test_app/components.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import idom
22

3-
from django_idom import register_component
43

5-
6-
@register_component
4+
@idom.component
75
def HelloWorld():
86
return idom.html.h1({"id": "hello-world"}, "Hello World!")
97

108

11-
@register_component
9+
@idom.component
1210
def Button():
1311
count, set_count = idom.hooks.use_state(0)
1412
return idom.html.div(
@@ -23,16 +21,16 @@ def Button():
2321
)
2422

2523

26-
@register_component
24+
@idom.component
2725
def ParametrizedComponent(x, y):
2826
total = x + y
2927
return idom.html.h1({"id": "parametrized-component", "data-value": total}, total)
3028

3129

32-
victory = idom.web.module_from_template("react", "victory-line", fallback="...")
30+
victory = idom.web.module_from_template("react", "victory-bar", fallback="...")
3331
VictoryBar = idom.web.export(victory, "VictoryBar")
3432

3533

36-
@register_component
34+
@idom.component
3735
def SimpleBarChart():
3836
return VictoryBar()

tests/test_app/templates/base.html

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515

1616
<body>
1717
<h1>IDOM Test Page</h1>
18-
<div>{% idom_view "test_app.views.HelloWorld" %}</div>
19-
<div>{% idom_view "test_app.views.Button" %}</div>
18+
<div>{% idom_view "test_app.components.HelloWorld" %}</div>
19+
<div>{% idom_view "test_app.components.Button" %}</div>
2020
<div>
21-
{% idom_view "test_app.views.ParametrizedComponent" x=123 y=456 %}
21+
{% idom_view "test_app.components.ParametrizedComponent" x=123 y=456 %}
2222
</div>
23-
<div>{% idom_view "test_app.views.SimpleBarChart" %}</div>
23+
<div>{% idom_view "test_app.components.SimpleBarChart" %}</div>
2424
</body>
2525
</html>

tests/test_app/views.py

-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
from django.http import HttpResponse
22
from django.template import loader
33

4-
import test_app.components
5-
64

75
def base_template(request):
86
context = {}

0 commit comments

Comments
 (0)