From 301c5f0eb35d52e48c279e29679e16151062ed76 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 3 Jul 2022 00:48:28 -0700 Subject: [PATCH 1/8] format hooks --- docs/features/hooks.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/features/hooks.md b/docs/features/hooks.md index e1cc4d04..7e1c1f55 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -1,5 +1,3 @@ -# Django Hooks - ???+ tip "Looking for more hooks?" Check out the [IDOM Core docs](https://idom-docs.herokuapp.com/docs/reference/hooks-api.html?highlight=hooks) on hooks! @@ -18,8 +16,6 @@ def MyComponent(): return html.div(my_websocket) ``` - - ## Use Scope This is a shortcut that returns the Websocket's `scope`. @@ -34,7 +30,6 @@ def MyComponent(): return html.div(my_scope) ``` - ## Use Location ??? info "This hook's behavior will be changed in a future update" From 27a2a945585f1db3d38f8bbbd6edd9ef8c6783f4 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 3 Jul 2022 00:48:59 -0700 Subject: [PATCH 2/8] Merge remote-tracking branch 'upstream/main' into orm-examples --- .github/workflows/test-docs.yml | 22 ++++++++++++ .github/workflows/{test.yml => test-src.yml} | 2 +- CHANGELOG.md | 2 +- README.md | 8 ++--- docs/features/components.md | 12 +++---- docs/features/hooks.md | 8 ++--- docs/features/settings.md | 27 ++++++++++++++ docs/features/templatetag.md | 16 +++++---- docs/installation/index.md | 14 +------- mkdocs.yml | 5 +-- src/django_idom/components.py | 11 +----- src/django_idom/templatetags/idom.py | 2 +- tests/test_app/components.py | 36 +++++++++---------- ...tatic-css-test.css => django-css-test.css} | 2 +- tests/test_app/static/django-js-test.js | 3 ++ tests/test_app/static/static-js-test.js | 3 -- tests/test_app/templates/base.html | 18 +++++----- tests/test_app/tests/test_components.py | 4 +-- 18 files changed, 113 insertions(+), 82 deletions(-) create mode 100644 .github/workflows/test-docs.yml rename .github/workflows/{test.yml => test-src.yml} (97%) create mode 100644 docs/features/settings.md rename tests/test_app/static/{static-css-test.css => django-css-test.css} (61%) create mode 100644 tests/test_app/static/django-js-test.js delete mode 100644 tests/test_app/static/static-js-test.js diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml new file mode 100644 index 00000000..967f7c8c --- /dev/null +++ b/.github/workflows/test-docs.yml @@ -0,0 +1,22 @@ +name: Test + +on: + push: + branches: + - main + pull_request: + branches: + - main + schedule: + - cron: "0 0 * * *" + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.x + - run: pip install -r requirements/build-docs.txt + - run: mkdocs build --verbose diff --git a/.github/workflows/test.yml b/.github/workflows/test-src.yml similarity index 97% rename from .github/workflows/test.yml rename to .github/workflows/test-src.yml index 2675c040..f5320f35 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test-src.yml @@ -11,7 +11,7 @@ on: - cron: "0 0 * * *" jobs: - test-python-versions: + source: runs-on: ubuntu-latest strategy: matrix: diff --git a/CHANGELOG.md b/CHANGELOG.md index bf2a083b..a283c7d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ Types of changes are to be listed in this order - Nothing (yet) -## [1.1.0] - 2022-06-25 +## [1.1.0] - 2022-07-01 ### Added diff --git a/README.md b/README.md index 58f86611..dfee8134 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Any Python web framework with Websockets can support IDOM. See below for what fr -You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. We recommend creating a `components.py` file within your chosen **Django app** to start out. Within this file, we will create a simple `HelloWorld` component. +You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. We recommend creating a `components.py` file within your chosen **Django app** to start out. Within this file, we will create a simple `hello_world` component. @@ -34,7 +34,7 @@ You'll need a file to define your [IDOM](https://github.com/idom-team/idom) comp from idom import component, html @component -def HelloWorld(recipient: str): +def hello_world(recipient: str): return html.h1(f"Hello {recipient}!") ``` @@ -46,7 +46,7 @@ def HelloWorld(recipient: str): In your **Django app**'s HTML template, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument. -Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `HelloWorld` (_in the previous example_) accepts a `recipient` argument. +Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `hello_world` (_in the previous example_) accepts a `recipient` argument. @@ -56,7 +56,7 @@ Additonally, you can pass in keyword arguments into your component function. For - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} + {% component "example_project.my_app.components.hello_world" recipient="World" %} ``` diff --git a/docs/features/components.md b/docs/features/components.md index 947a4431..dc697162 100644 --- a/docs/features/components.md +++ b/docs/features/components.md @@ -7,7 +7,7 @@ from idom import component, html from django_idom.components import django_css @component -def MyComponent(): +def my_component(): return html.div( django_css("css/buttons.css"), html.button("My Button!"), @@ -29,7 +29,7 @@ def MyComponent(): from django.templatetags.static import static @component - def MyComponent(): + def my_component(): return html.div( html.link({"rel": "stylesheet", "href": static("css/buttons.css")}), html.button("My Button!"), @@ -46,7 +46,7 @@ def MyComponent(): from idom import component, html @component - def MyComponent(): + def my_component(): return html.div( html.link({"rel": "stylesheet", "href": "https://example.com/external-styles.css"}), html.button("My Button!"), @@ -68,7 +68,7 @@ from idom import component, html from django_idom.components import django_js @component -def MyComponent(): +def my_component(): return html.div( html.button("My Button!"), django_js("js/scripts.js"), @@ -90,7 +90,7 @@ def MyComponent(): from django.templatetags.static import static @component - def MyComponent(): + def my_component(): return html.div( html.script({"src": static("js/scripts.js")}), html.button("My Button!"), @@ -107,7 +107,7 @@ def MyComponent(): from idom import component, html @component - def MyComponent(): + def my_component(): return html.div( html.script({"src": static("https://example.com/external-scripts.js")}), html.button("My Button!"), diff --git a/docs/features/hooks.md b/docs/features/hooks.md index 7e1c1f55..7a0d8a99 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -11,7 +11,7 @@ from idom import component, html from django_idom.hooks import use_websocket @component -def MyComponent(): +def my_component(): my_websocket = use_websocket() return html.div(my_websocket) ``` @@ -25,7 +25,7 @@ from idom import component, html from django_idom.hooks import use_scope @component -def MyComponent(): +def my_component(): my_scope = use_scope() return html.div(my_scope) ``` @@ -34,7 +34,7 @@ def MyComponent(): ??? info "This hook's behavior will be changed in a future update" - This hook will be updated to return the browser's current URL. This will come in alongside our built-in [Single Page Application (SPA) support](https://github.com/idom-team/idom/issues/569). + This hook will be updated to return the browser's current URL. This change will come in alongside [IDOM URL routing support](https://github.com/idom-team/idom/issues/569). This is a shortcut that returns the Websocket's `path`. @@ -43,7 +43,7 @@ from idom import component, html from django_idom.hooks import use_location @component -def MyComponent(): +def my_component(): my_location = use_location() return html.div(my_location) ``` diff --git a/docs/features/settings.md b/docs/features/settings.md new file mode 100644 index 00000000..b003ae3c --- /dev/null +++ b/docs/features/settings.md @@ -0,0 +1,27 @@ +Django IDOM uses your **Django project's** `settings.py` file to modify some behaviors of IDOM. + +Here are the configurable variables that are available. + + + +```python title="settings.py" +# If "idom" cache is not configured, then we'll use "default" instead +CACHES = { +"idom": {"BACKEND": ...}, +} + +# Maximum seconds between two reconnection attempts that would cause the client give up. +# 0 will disable reconnection. +IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 + +# The URL for IDOM to serve websockets +IDOM_WEBSOCKET_URL = "idom/" +``` + + + +??? question "Do I need to modify my settings?" + + The default configuration of IDOM is adequate for the majority of use cases. + + You should only consider changing settings when the necessity arises. diff --git a/docs/features/templatetag.md b/docs/features/templatetag.md index 26a2f4ad..5f917f92 100644 --- a/docs/features/templatetag.md +++ b/docs/features/templatetag.md @@ -14,16 +14,16 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ```python title="views.py" def example_view(): - context_vars = {"DontDoThis": "example_project.my_app.components.HelloWorld"} + context_vars = {"dont_do_this": "example_project.my_app.components.hello_world"} return render(request, "my-template.html", context_vars) ``` ```jinja title="my-template.html" - {% component DontDoThis recipient="World" %} + {% component dont_do_this recipient="World" %} - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} + {% component "example_project.my_app.components.hello_world" recipient="World" %} ``` @@ -38,7 +38,7 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca ```jinja title="my-template.html" ... - {% component "example.components.MyComponent" class="my-html-class" key=123 %} + {% component "example.components.my_component" class="my-html-class" key=123 %} ... ``` @@ -54,15 +54,17 @@ Integrated within Django IDOM, we bundle a template tag. Within this tag, you ca - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} - {% component "example_project.my_app_2.components.ClassComponent" class="bold small-font" %} -
{% component "example_project.my_app_3.components.SimpleComponent" %}
+ {% component "example_project.my_app.components.hello_world" recipient="World" %} + {% component "example_project.my_app_2.components.class_component" class="bold small-font" %} +
{% component "example_project.my_app_3.components.simple_component" %}
``` But keep in mind, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one central component within your `#!html ` tag. + Additionally, the components in the example above will not be able to interact with each other, except through database queries. + diff --git a/docs/installation/index.md b/docs/installation/index.md index a2a6e391..e0cdfc1e 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -43,19 +43,7 @@ INSTALLED_APPS = [ Below are a handful of values you can change within `settings.py` to modify the behavior of IDOM. - ```python title="settings.py" - # If "idom" cache is not configured, then we'll use "default" instead - CACHES = { - "idom": {"BACKEND": ...}, - } - - # Maximum seconds between two reconnection attempts that would cause the client give up. - # 0 will disable reconnection. - IDOM_WS_MAX_RECONNECT_TIMEOUT = 604800 - - # The URL for IDOM to serve websockets - IDOM_WEBSOCKET_URL = "idom/" - ``` + {% include-markdown "../features/settings.md" start="" end="" %} --- diff --git a/mkdocs.yml b/mkdocs.yml index 50cef329..9cf9d38b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,6 +12,7 @@ nav: - Components: features/components.md - Hooks: features/hooks.md - Template Tag: features/templatetag.md + - Settings: features/settings.md - Contribute: - Code: contribute/django-idom.md - Docs: contribute/docs.md @@ -24,14 +25,14 @@ theme: - media: "(prefers-color-scheme: dark)" scheme: slate toggle: - icon: material/toggle-switch + icon: material/white-balance-sunny name: Switch to light mode primary: deep-orange accent: orange - media: "(prefers-color-scheme: light)" scheme: default toggle: - icon: material/toggle-switch-off-outline + icon: material/weather-night name: Switch to dark mode primary: black features: diff --git a/src/django_idom/components.py b/src/django_idom/components.py index dab9a5d0..1433d30a 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -14,16 +14,7 @@ def django_css(static_path: str): static_path: The path to the static file. This path is identical to what you would use on a `static` template tag. """ - return html._( - html.script( - """ - let parentTag = document.currentScript; - console.log(parentTag); - //parentTag.attachShadow({ mode: 'open' }); - """ - ), - html.style(_cached_static_contents(static_path)), - ) + return html._(html.style(_cached_static_contents(static_path))) @component diff --git a/src/django_idom/templatetags/idom.py b/src/django_idom/templatetags/idom.py index 7b8f3610..5e6b7ced 100644 --- a/src/django_idom/templatetags/idom.py +++ b/src/django_idom/templatetags/idom.py @@ -26,7 +26,7 @@ def component(_component_id_, **kwargs): - {% component "example_project.my_app.components.HelloWorld" recipient="World" %} + {% component "example_project.my_app.components.hello_world" recipient="World" %} """ diff --git a/tests/test_app/components.py b/tests/test_app/components.py index 687bfea2..a2491c17 100644 --- a/tests/test_app/components.py +++ b/tests/test_app/components.py @@ -4,12 +4,12 @@ @idom.component -def HelloWorld(): +def hello_world(): return idom.html.h1({"id": "hello-world"}, "Hello World!") @idom.component -def Button(): +def button(): count, set_count = idom.hooks.use_state(0) return idom.html.div( idom.html.button( @@ -24,7 +24,7 @@ def Button(): @idom.component -def ParametrizedComponent(x, y): +def parameterized_component(x, y): total = x + y return idom.html.h1({"id": "parametrized-component", "data-value": total}, total) @@ -34,64 +34,64 @@ def ParametrizedComponent(x, y): @idom.component -def SimpleBarChart(): +def simple_bar_chart(): return VictoryBar() @idom.component -def UseWebsocket(): +def use_websocket(): ws = django_idom.hooks.use_websocket() ws.scope = "..." success = bool(ws.scope and ws.close and ws.disconnect and ws.view_id) return idom.html.div( {"id": "use-websocket", "data-success": success}, idom.html.hr(), - f"UseWebsocket: {ws}", + f"use_websocket: {ws}", idom.html.hr(), ) @idom.component -def UseScope(): +def use_scope(): scope = django_idom.hooks.use_scope() success = len(scope) >= 10 and scope["type"] == "websocket" return idom.html.div( {"id": "use-scope", "data-success": success}, - f"UseScope: {scope}", + f"use_scope: {scope}", idom.html.hr(), ) @idom.component -def UseLocation(): +def use_location(): location = django_idom.hooks.use_location() success = bool(location) return idom.html.div( {"id": "use-location", "data-success": success}, - f"UseLocation: {location}", + f"use_location: {location}", idom.html.hr(), ) @idom.component -def StaticCSS(): +def django_css(): return idom.html.div( - {"id": "static-css"}, - django_idom.components.django_css("static-css-test.css"), - idom.html.div({"style": {"display": "inline"}}, "StaticCSS: "), + {"id": "django-css"}, + django_idom.components.django_css("django-css-test.css"), + idom.html.div({"style": {"display": "inline"}}, "django_css: "), idom.html.button("This text should be blue."), idom.html.hr(), ) @idom.component -def StaticJS(): +def django_js(): success = False return idom.html._( idom.html.div( - {"id": "static-js", "data-success": success}, - f"StaticJS: {success}", - django_idom.components.django_js("static-js-test.js"), + {"id": "django-js", "data-success": success}, + f"django_js: {success}", + django_idom.components.django_js("django-js-test.js"), ), idom.html.hr(), ) diff --git a/tests/test_app/static/static-css-test.css b/tests/test_app/static/django-css-test.css similarity index 61% rename from tests/test_app/static/static-css-test.css rename to tests/test_app/static/django-css-test.css index d5565d70..af68e6ed 100644 --- a/tests/test_app/static/static-css-test.css +++ b/tests/test_app/static/django-css-test.css @@ -1,3 +1,3 @@ -#static-css button { +#django-css button { color: rgba(0, 0, 255, 1); } diff --git a/tests/test_app/static/django-js-test.js b/tests/test_app/static/django-js-test.js new file mode 100644 index 00000000..1d59eb31 --- /dev/null +++ b/tests/test_app/static/django-js-test.js @@ -0,0 +1,3 @@ +let el = document.body.querySelector("#django-js"); +el.textContent = "django_js: True"; +el.dataset.success = "true"; diff --git a/tests/test_app/static/static-js-test.js b/tests/test_app/static/static-js-test.js deleted file mode 100644 index b4423acf..00000000 --- a/tests/test_app/static/static-js-test.js +++ /dev/null @@ -1,3 +0,0 @@ -let el = document.body.querySelector("#static-js"); -el.textContent = "StaticJS: True"; -el.dataset.success = "true"; diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html index c597cdf9..e6960c14 100644 --- a/tests/test_app/templates/base.html +++ b/tests/test_app/templates/base.html @@ -12,15 +12,15 @@

IDOM Test Page

-
{% component "test_app.components.HelloWorld" class="hello-world" %}
-
{% component "test_app.components.Button" class="button" %}
-
{% component "test_app.components.ParametrizedComponent" class="parametarized-component" x=123 y=456 %}
-
{% component "test_app.components.SimpleBarChart" %}
-
{% component "test_app.components.UseWebsocket" %}
-
{% component "test_app.components.UseScope" %}
-
{% component "test_app.components.UseLocation" %}
-
{% component "test_app.components.StaticCSS" %}
-
{% component "test_app.components.StaticJS" %}
+
{% component "test_app.components.hello_world" class="hello-world" %}
+
{% component "test_app.components.button" class="button" %}
+
{% component "test_app.components.parameterized_component" class="parametarized-component" x=123 y=456 %}
+
{% component "test_app.components.simple_bar_chart" %}
+
{% component "test_app.components.use_websocket" %}
+
{% component "test_app.components.use_scope" %}
+
{% component "test_app.components.use_location" %}
+
{% component "test_app.components.django_css" %}
+
{% component "test_app.components.django_js" %}
diff --git a/tests/test_app/tests/test_components.py b/tests/test_app/tests/test_components.py index 33a8c6e8..8ed89efa 100644 --- a/tests/test_app/tests/test_components.py +++ b/tests/test_app/tests/test_components.py @@ -60,13 +60,13 @@ def test_use_location(self): self.assertEqual(element.get_attribute("data-success"), "true") def test_static_css(self): - element = self.driver.find_element_by_css_selector("#static-css button") + element = self.driver.find_element_by_css_selector("#django-css button") self.assertEqual( element.value_of_css_property("color"), "rgba(0, 0, 255, 1)" ) def test_static_js(self): - element = self.driver.find_element_by_id("static-js") + element = self.driver.find_element_by_id("django-js") self.assertEqual(element.get_attribute("data-success"), "true") From ba9de07d5431c778b048c9fe84f59f27d6fef2b2 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 3 Jul 2022 01:47:18 -0700 Subject: [PATCH 3/8] orm usage docs --- .github/pull_request_template.md | 4 +-- docs/features/hooks.md | 4 ++- docs/features/orm.md | 46 ++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 docs/features/orm.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 92ac3c3d..33212937 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,8 +1,8 @@ -# Description +## Description A summary of the changes. -# Checklist: +## Checklist: Please update this checklist as you complete each item: diff --git a/docs/features/hooks.md b/docs/features/hooks.md index 7a0d8a99..ad4afb34 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -34,7 +34,9 @@ def my_component(): ??? info "This hook's behavior will be changed in a future update" - This hook will be updated to return the browser's current URL. This change will come in alongside [IDOM URL routing support](https://github.com/idom-team/idom/issues/569). + This hook will be updated to return the browser's current URL. This change will come in alongside IDOM URL routing support. + + Check out [idom-team/idom#569](https://github.com/idom-team/idom/issues/569) for more information. This is a shortcut that returns the Websocket's `path`. diff --git a/docs/features/orm.md b/docs/features/orm.md new file mode 100644 index 00000000..b2fade25 --- /dev/null +++ b/docs/features/orm.md @@ -0,0 +1,46 @@ +??? info "Our suggested ORM access method will be changed in a future update" + + The Django IDOM team is currently assessing the optimal way to integrate the [Django ORM](https://docs.djangoproject.com/en/dev/topics/db/queries/) with our React-style framework. + + This docs page exists to demonstrate how the ORM should be used with the current version of Django IDOM. + + Check out [idom-team/django-idom#79](https://github.com/idom-team/django-idom/issues/79) for more information. + +This is the suggested method of using the Django ORM with Django IDOM. + +```python title="components.py" +from channels.db import database_sync_to_async +from example_project.my_app.models import Category +from idom import component, hooks, html + + +@component +def simple_list(): + categories, set_categories = hooks.use_state(None) + + @hooks.use_effect + @database_sync_to_async + def get_categories(): + if categories: + return + set_categories(Category.objects.all()) + + if not categories: + return html.h2("Loading...") + + return html.ul( + [html.li(category.name, key=category.name) for category in categories] + ) +``` + +??? question "Why can't I make ORM calls without hooks?" + + Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a `SynchronousOnlyOperation` exception. + + This may be resolved in a future version of Django with a natively asynchronous ORM. + +??? question "What is an ORM?" + + A Python **Object Relational Mapper** is an API for your code to access a database. + + See the [Django ORM documentation](https://docs.djangoproject.com/en/dev/topics/db/queries/) for more information. diff --git a/mkdocs.yml b/mkdocs.yml index 9cf9d38b..e4c6b059 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -11,6 +11,7 @@ nav: - Exclusive Features: - Components: features/components.md - Hooks: features/hooks.md + - ORM: features/orm.md - Template Tag: features/templatetag.md - Settings: features/settings.md - Contribute: From 92e2ce1649252234e34cbf6ff54f0cb10bbc9b82 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 3 Jul 2022 01:54:53 -0700 Subject: [PATCH 4/8] format --- docs/features/hooks.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/features/hooks.md b/docs/features/hooks.md index 7eefabc3..ad4afb34 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -37,7 +37,6 @@ def my_component(): This hook will be updated to return the browser's current URL. This change will come in alongside IDOM URL routing support. Check out [idom-team/idom#569](https://github.com/idom-team/idom/issues/569) for more information. - This is a shortcut that returns the Websocket's `path`. From 2b53af13ec6c5814aaf5d27bc80a6a142092904e Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 3 Jul 2022 02:00:24 -0700 Subject: [PATCH 5/8] remove repetitious wording --- docs/features/orm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/orm.md b/docs/features/orm.md index b2fade25..3a7e1903 100644 --- a/docs/features/orm.md +++ b/docs/features/orm.md @@ -6,7 +6,7 @@ Check out [idom-team/django-idom#79](https://github.com/idom-team/django-idom/issues/79) for more information. -This is the suggested method of using the Django ORM with Django IDOM. +This is the suggested method of using the Django ORM with your components. ```python title="components.py" from channels.db import database_sync_to_async From 2829294c54ad82b011f5698ff6a0dbd9467e543c Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 3 Jul 2022 05:42:10 -0700 Subject: [PATCH 6/8] force SQL execution using list --- docs/features/orm.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/features/orm.md b/docs/features/orm.md index 3a7e1903..8ff1aa3f 100644 --- a/docs/features/orm.md +++ b/docs/features/orm.md @@ -23,7 +23,7 @@ def simple_list(): def get_categories(): if categories: return - set_categories(Category.objects.all()) + set_categories(list(Category.objects.all())) if not categories: return html.h2("Loading...") @@ -44,3 +44,9 @@ def simple_list(): A Python **Object Relational Mapper** is an API for your code to access a database. See the [Django ORM documentation](https://docs.djangoproject.com/en/dev/topics/db/queries/) for more information. + +??? question "Why did this example use `list()` within `set_categories`?" + + [Django's ORM is lazy](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy). Thus, `list()` is used to ensure that the query is executed while the hook is executing. + + Failure to do this will result in `SynchronousOnlyOperation` when attempting to access your data. From aff5e260db65437755cfda22be70bd97c2edda8f Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 3 Jul 2022 05:43:56 -0700 Subject: [PATCH 7/8] wordsmith --- docs/features/orm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/orm.md b/docs/features/orm.md index 8ff1aa3f..225b0ebd 100644 --- a/docs/features/orm.md +++ b/docs/features/orm.md @@ -47,6 +47,6 @@ def simple_list(): ??? question "Why did this example use `list()` within `set_categories`?" - [Django's ORM is lazy](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy). Thus, `list()` is used to ensure that the query is executed while the hook is executing. + [Django's ORM is lazy](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy). Thus, `list()` is used to ensure that the database query is executed while within the hook. Failure to do this will result in `SynchronousOnlyOperation` when attempting to access your data. From 1e93260f8e9af6d6880a42885d44efd540cb6210 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 3 Jul 2022 05:46:43 -0700 Subject: [PATCH 8/8] did -> does --- docs/features/orm.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/features/orm.md b/docs/features/orm.md index 225b0ebd..056db7f1 100644 --- a/docs/features/orm.md +++ b/docs/features/orm.md @@ -33,6 +33,12 @@ def simple_list(): ) ``` +??? question "Why does this example use `list()` within `set_categories`?" + + [Django's ORM is lazy](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy). Thus, `list()` is used to ensure that the database query is executed while within the hook. + + Failure to do this will result in `SynchronousOnlyOperation` when attempting to access your data. + ??? question "Why can't I make ORM calls without hooks?" Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a `SynchronousOnlyOperation` exception. @@ -44,9 +50,3 @@ def simple_list(): A Python **Object Relational Mapper** is an API for your code to access a database. See the [Django ORM documentation](https://docs.djangoproject.com/en/dev/topics/db/queries/) for more information. - -??? question "Why did this example use `list()` within `set_categories`?" - - [Django's ORM is lazy](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy). Thus, `list()` is used to ensure that the database query is executed while within the hook. - - Failure to do this will result in `SynchronousOnlyOperation` when attempting to access your data.