diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 17080b52..63a412e0 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -46,7 +46,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -59,7 +59,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ uses: github/codeql-action/autobuild@v3
# âšī¸ Command-line programs to run using the OS shell.
# đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -72,6 +72,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/publish-develop-docs.yml b/.github/workflows/publish-develop-docs.yml
index 53c5aa16..43d114af 100644
--- a/.github/workflows/publish-develop-docs.yml
+++ b/.github/workflows/publish-develop-docs.yml
@@ -5,7 +5,7 @@ on:
branches:
- main
jobs:
- deploy:
+ publish-develop-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -17,12 +17,13 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: 3.x
- - run: pip install -r requirements/build-docs.txt
- - name: Publish Develop Docs
+ - name: Install dependencies
+ run: pip install hatch
+ - name: Configure Git
run: |
git config user.name github-actions
git config user.email github-actions@github.com
- cd docs
- mike deploy --push develop
+ - name: Publish Develop Docs
+ run: hatch run docs:deploy_develop
concurrency:
group: publish-docs
diff --git a/.github/workflows/publish-release-docs.yml b/.github/workflows/publish-latest-docs.yml
similarity index 73%
rename from .github/workflows/publish-release-docs.yml
rename to .github/workflows/publish-latest-docs.yml
index 93df3e2a..a4945b6f 100644
--- a/.github/workflows/publish-release-docs.yml
+++ b/.github/workflows/publish-latest-docs.yml
@@ -1,11 +1,11 @@
-name: Publish Release Docs
+name: Publish Latest Docs
on:
release:
types: [published]
jobs:
- deploy:
+ publish-latest-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -17,12 +17,13 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: 3.x
- - run: pip install -r requirements/build-docs.txt
- - name: Publish ${{ github.event.release.name }} Docs
+ - name: Install dependencies
+ run: pip install hatch
+ - name: Configure Git
run: |
git config user.name github-actions
git config user.email github-actions@github.com
- cd docs
- mike deploy --push --update-aliases ${{ github.event.release.name }} latest
+ - name: Publish ${{ github.event.release.name }} Docs
+ run: hatch run docs:deploy_latest ${{ github.ref_name }}
concurrency:
group: publish-docs
diff --git a/.github/workflows/publish-py.yml b/.github/workflows/publish-py.yml
deleted file mode 100644
index 6a86db98..00000000
--- a/.github/workflows/publish-py.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-# This workflows will upload a Python Package using Twine when a release is created
-# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
-
-name: Publish Python
-
-on:
- release:
- types: [published]
-
-jobs:
- release-package:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: oven-sh/setup-bun@v2
- with:
- bun-version: latest
- - name: Set up Python
- uses: actions/setup-python@v5
- with:
- python-version: "3.x"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -r requirements/build-pkg.txt
- - name: Build and publish
- env:
- TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
- TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
- run: |
- python -m build --sdist --wheel --outdir dist .
- twine upload dist/*
diff --git a/.github/workflows/publish-python.yml b/.github/workflows/publish-python.yml
new file mode 100644
index 00000000..e20affbb
--- /dev/null
+++ b/.github/workflows/publish-python.yml
@@ -0,0 +1,27 @@
+name: Publish Python
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ publish-python:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: oven-sh/setup-bun@v2
+ with:
+ bun-version: latest
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.x"
+ - name: Install dependencies
+ run: pip install hatch
+ - name: Build Package
+ run: hatch build --clean
+ - name: Publish to PyPI
+ env:
+ HATCH_INDEX_USER: ${{ secrets.PYPI_USERNAME }}
+ HATCH_INDEX_AUTH: ${{ secrets.PYPI_PASSWORD }}
+ run: hatch publish --yes
diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml
index 66a5c942..5a2d4fd4 100644
--- a/.github/workflows/test-docs.yml
+++ b/.github/workflows/test-docs.yml
@@ -7,8 +7,6 @@ on:
pull_request:
branches:
- main
- schedule:
- - cron: "0 0 * * *"
jobs:
docs:
@@ -23,20 +21,12 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: 3.x
- # - name: Check docs links
- # uses: umbrelladocs/action-linkspector@v1
- # with:
- # github_token: ${{ secrets.github_token }}
- # reporter: github-pr-review
- # fail_on_error: false
+ - name: Install Python Dependencies
+ run: pip install hatch
+ # DISABLED DUE TO DJANGO DOCS CONSTANTLY THROWING 429 ERRORS
+ # - name: Check documentation links
+ # run: hatch run docs:linkcheck
- name: Check docs build
- run: |
- pip install -r requirements/build-docs.txt
- cd docs
- mkdocs build --strict
+ run: hatch run docs:build
- name: Check docs examples
- run: |
- pip install -r requirements/check-types.txt
- pip install -r requirements/check-style.txt
- mypy --show-error-codes docs/examples/python/
- ruff check docs/examples/python/
+ run: hatch fmt docs --check
diff --git a/.github/workflows/test-javascript.yml b/.github/workflows/test-javascript.yml
new file mode 100644
index 00000000..8e204dcb
--- /dev/null
+++ b/.github/workflows/test-javascript.yml
@@ -0,0 +1,25 @@
+name: Test
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ javascript:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: oven-sh/setup-bun@v2
+ with:
+ bun-version: latest
+ - uses: actions/setup-python@v5
+ with:
+ python-version: 3.x
+ - name: Install Python Dependencies
+ run: pip install hatch
+ - name: Run Tests
+ run: hatch run javascript:check
diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml
new file mode 100644
index 00000000..ac8d77b6
--- /dev/null
+++ b/.github/workflows/test-python.yml
@@ -0,0 +1,63 @@
+name: Test
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+ schedule:
+ - cron: "0 0 * * *"
+
+jobs:
+ python-source:
+ runs-on: ${{ matrix.operating-system }}
+ strategy:
+ matrix:
+ python-version: ["3.9", "3.10", "3.11", "3.12"]
+ settings-module: ["single_db", "multi_db"]
+ operating-system: ["ubuntu-latest", "windows-latest"]
+ steps:
+ - uses: actions/checkout@v4
+ - uses: oven-sh/setup-bun@v2
+ with:
+ bun-version: latest
+ - name: Use Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install Python Dependencies
+ run: pip install hatch
+ - name: Run Single DB Tests
+ run: hatch test --python ${{ matrix.python-version }} --ds=test_app.settings_${{matrix.settings-module}} -v
+
+ python-formatting:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: oven-sh/setup-bun@v2
+ with:
+ bun-version: latest
+ - uses: actions/setup-python@v5
+ with:
+ python-version: 3.x
+ - name: Install Python Dependencies
+ run: pip install hatch
+ - name: Check Python formatting
+ run: hatch fmt src tests --check
+
+ python-types:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: oven-sh/setup-bun@v2
+ with:
+ bun-version: latest
+ - uses: actions/setup-python@v5
+ with:
+ python-version: 3.x
+ - name: Install Python Dependencies
+ run: pip install hatch
+ - name: Run Python type checker
+ run: hatch run python:type_check
diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-src.yml
deleted file mode 100644
index 5eb2e67a..00000000
--- a/.github/workflows/test-src.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: Test
-
-on:
- push:
- branches:
- - main
- pull_request:
- branches:
- - main
- schedule:
- - cron: "0 0 * * *"
-
-jobs:
- source:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version: ["3.9", "3.10", "3.11", "3.12"]
- steps:
- - uses: actions/checkout@v4
- - uses: oven-sh/setup-bun@v2
- with:
- bun-version: latest
- - name: Use Python ${{ matrix.python-version }}
- uses: actions/setup-python@v5
- with:
- python-version: ${{ matrix.python-version }}
- - name: Install Python Dependencies
- run: pip install -r requirements/test-run.txt
- - name: Run Tests
- run: nox -t test
diff --git a/.gitignore b/.gitignore
index e3cbc599..e675e09a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# ReactPy-Django Build Artifacts
-src/reactpy_django/static/reactpy_django/client.js
+src/reactpy_django/static/reactpy_django/index.js
+src/reactpy_django/static/reactpy_django/index.js.map
src/reactpy_django/static/reactpy_django/pyscript
src/reactpy_django/static/reactpy_django/morphdom
diff --git a/.linkspector.yml b/.linkspector.yml
deleted file mode 100644
index 6c0747e7..00000000
--- a/.linkspector.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-dirs:
- - ./docs
-files:
- - README.md
- - CHANGELOG.md
-useGitIgnore: true
-modifiedFilesOnly: false
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5342e003..f3a0ff04 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,33 +10,70 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+
+
+
+## [Unreleased]
+
+### Changed
+
+- Updated the interface for `reactpy.hooks.use_channel_layer` to be more intuitive.
+ - Arguments now must be provided as keyworded arguments.
+ - The `name` argument has been renamed to `channel`.
+ - The `group_name` argument has been renamed to `group`.
+ - The `group_add` and `group_discard` arguments have been removed for simplicity.
+
+### [5.2.1] - 2025-01-10
+
+### Changed
+
+- Use the latest version of `@reactpy/client` which includes a fix for needless client-side component re-creation.
+
+### [5.2.0] - 2024-12-29
### Added
-- for new features.
+
+- User login/logout features!
+ - `reactpy_django.hooks.use_auth` to provide **persistent** `login` and `logout` functionality to your components.
+ - `settings.py:REACTPY_AUTH_TOKEN_MAX_AGE` to control the maximum seconds before ReactPy's login token expires.
+ - `settings.py:REACTPY_CLEAN_AUTH_TOKENS` to control whether ReactPy should clean up expired authentication tokens during automatic cleanups.
+- Automatically convert Django forms to ReactPy forms via the new `reactpy_django.components.django_form` component!
+- The ReactPy component tree can now be forcibly re-rendered via the new `reactpy_django.hooks.use_rerender` hook.
### Changed
-- for changes in existing functionality.
-### Deprecated
-- for soon-to-be removed features.
+- Refactoring of internal code to improve maintainability. No changes to publicly documented API.
-### Removed
-- for removed features.
+### Fixed
+
+- Fixed bug where pre-rendered components could generate a `SynchronousOnlyOperation` exception if they access a freshly logged out Django user object.
+
+## [5.1.1] - 2024-12-02
### Fixed
-- for bug fixes.
-### Security
-- for vulnerability fixes.
+- Fixed regression from the previous release where components would sometimes not output debug messages when `settings.py:DEBUG` is enabled.
-Don't forget to remove deprecated code on each major release!
--->
+### Changed
-
+- Set upper limit on ReactPy version to `<2.0.0`.
+- ReactPy web modules are now streamed in chunks.
+- ReactPy web modules are now streamed using asynchronous file reading to improve performance.
+- Performed refactoring to utilize `ruff` as this repository's linter.
-## [Unreleased]
+## [5.1.0] - 2024-11-24
+
+### Added
+
+- `settings.py:REACTPY_ASYNC_RENDERING` to enable asynchronous rendering of components.
+
+### Changed
-- Nothing (yet)!
+- Bumped the minimum ReactPy version to `1.1.0`.
## [5.0.0] - 2024-10-22
@@ -519,7 +556,11 @@ Don't forget to remove deprecated code on each major release!
- Support for IDOM within the Django
-[Unreleased]: https://github.com/reactive-python/reactpy-django/compare/5.0.0...HEAD
+[Unreleased]: https://github.com/reactive-python/reactpy-django/compare/5.2.1...HEAD
+[5.2.1]: https://github.com/reactive-python/reactpy-django/compare/5.2.0...5.2.1
+[5.2.0]: https://github.com/reactive-python/reactpy-django/compare/5.1.1...5.2.0
+[5.1.1]: https://github.com/reactive-python/reactpy-django/compare/5.1.0...5.1.1
+[5.1.0]: https://github.com/reactive-python/reactpy-django/compare/5.0.0...5.1.0
[5.0.0]: https://github.com/reactive-python/reactpy-django/compare/4.0.0...5.0.0
[4.0.0]: https://github.com/reactive-python/reactpy-django/compare/3.8.1...4.0.0
[3.8.1]: https://github.com/reactive-python/reactpy-django/compare/3.8.0...3.8.1
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index ddcb7f8d..00000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,3 +0,0 @@
-include src/reactpy_django/py.typed
-recursive-include src/reactpy_django/static *
-recursive-include src/reactpy_django/templates *.html
diff --git a/README.md b/README.md
index d3d2a1a9..3ebd3faf 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# ReactPy-Django
-
-
+
+
@@ -28,8 +28,9 @@
- [Customizable reconnection behavior](https://reactive-python.github.io/reactpy-django/latest/reference/settings/#stability-settings)
- [Customizable disconnection behavior](https://reactive-python.github.io/reactpy-django/latest/reference/template-tag)
- [Multiple root components](https://reactive-python.github.io/reactpy-django/latest/reference/template-tag/)
-- [Cross-process communication/signaling (Channel Layers)](https://reactive-python.github.io/reactpy-django/latest/reference/hooks/#use-channel-layer)
+- [Cross-process communication/signaling](https://reactive-python.github.io/reactpy-django/latest/reference/hooks/#use-channel-layer)
- [Django view to ReactPy component conversion](https://reactive-python.github.io/reactpy-django/latest/reference/components/#view-to-component)
+- [Django form to ReactPy component conversion](https://reactive-python.github.io/reactpy-django/latest/reference/components/#django-form)
- [Django static file access](https://reactive-python.github.io/reactpy-django/latest/reference/components/#django-css)
- [Django database access](https://reactive-python.github.io/reactpy-django/latest/reference/hooks/#use-query)
diff --git a/docs/examples/html/django_form_bootstrap.html b/docs/examples/html/django_form_bootstrap.html
new file mode 100644
index 00000000..6aba84ca
--- /dev/null
+++ b/docs/examples/html/django_form_bootstrap.html
@@ -0,0 +1,11 @@
+{% load django_bootstrap5 %}
+
+
+{% bootstrap_css %}
+{% bootstrap_javascript %}
+
+
+{% bootstrap_form form %}
+{% bootstrap_button button_type="submit" content="OK" %}
+{% bootstrap_button button_type="reset" content="Reset" %}
diff --git a/docs/examples/html/pyscript-component.html b/docs/examples/html/pyscript_component.html
similarity index 100%
rename from docs/examples/html/pyscript-component.html
rename to docs/examples/html/pyscript_component.html
diff --git a/docs/examples/html/pyscript-initial-object.html b/docs/examples/html/pyscript_initial_object.html
similarity index 100%
rename from docs/examples/html/pyscript-initial-object.html
rename to docs/examples/html/pyscript_initial_object.html
diff --git a/docs/examples/html/pyscript-initial-string.html b/docs/examples/html/pyscript_initial_string.html
similarity index 100%
rename from docs/examples/html/pyscript-initial-string.html
rename to docs/examples/html/pyscript_initial_string.html
diff --git a/docs/examples/html/pyscript-local-import.html b/docs/examples/html/pyscript_local_import.html
similarity index 100%
rename from docs/examples/html/pyscript-local-import.html
rename to docs/examples/html/pyscript_local_import.html
diff --git a/docs/examples/html/pyscript-multiple-files.html b/docs/examples/html/pyscript_multiple_files.html
similarity index 100%
rename from docs/examples/html/pyscript-multiple-files.html
rename to docs/examples/html/pyscript_multiple_files.html
diff --git a/docs/examples/html/pyscript-root.html b/docs/examples/html/pyscript_root.html
similarity index 100%
rename from docs/examples/html/pyscript-root.html
rename to docs/examples/html/pyscript_root.html
diff --git a/docs/examples/html/pyscript-setup.html b/docs/examples/html/pyscript_setup.html
similarity index 100%
rename from docs/examples/html/pyscript-setup.html
rename to docs/examples/html/pyscript_setup.html
diff --git a/docs/examples/html/pyscript-setup-config-object.html b/docs/examples/html/pyscript_setup_config_object.html
similarity index 100%
rename from docs/examples/html/pyscript-setup-config-object.html
rename to docs/examples/html/pyscript_setup_config_object.html
diff --git a/docs/examples/html/pyscript-setup-config-string.html b/docs/examples/html/pyscript_setup_config_string.html
similarity index 100%
rename from docs/examples/html/pyscript-setup-config-string.html
rename to docs/examples/html/pyscript_setup_config_string.html
diff --git a/docs/examples/html/pyscript-setup-dependencies.html b/docs/examples/html/pyscript_setup_dependencies.html
similarity index 100%
rename from docs/examples/html/pyscript-setup-dependencies.html
rename to docs/examples/html/pyscript_setup_dependencies.html
diff --git a/docs/examples/html/pyscript-setup-extra-js-object.html b/docs/examples/html/pyscript_setup_extra_js_object.html
similarity index 100%
rename from docs/examples/html/pyscript-setup-extra-js-object.html
rename to docs/examples/html/pyscript_setup_extra_js_object.html
diff --git a/docs/examples/html/pyscript-setup-extra-js-string.html b/docs/examples/html/pyscript_setup_extra_js_string.html
similarity index 100%
rename from docs/examples/html/pyscript-setup-extra-js-string.html
rename to docs/examples/html/pyscript_setup_extra_js_string.html
diff --git a/docs/examples/html/pyscript-setup-local-interpreter.html b/docs/examples/html/pyscript_setup_local_interpreter.html
similarity index 100%
rename from docs/examples/html/pyscript-setup-local-interpreter.html
rename to docs/examples/html/pyscript_setup_local_interpreter.html
diff --git a/docs/examples/html/pyscript-ssr-parent.html b/docs/examples/html/pyscript_ssr_parent.html
similarity index 100%
rename from docs/examples/html/pyscript-ssr-parent.html
rename to docs/examples/html/pyscript_ssr_parent.html
diff --git a/docs/examples/html/pyscript-tag.html b/docs/examples/html/pyscript_tag.html
similarity index 100%
rename from docs/examples/html/pyscript-tag.html
rename to docs/examples/html/pyscript_tag.html
diff --git a/docs/examples/python/configure-asgi.py b/docs/examples/python/configure_asgi.py
similarity index 77%
rename from docs/examples/python/configure-asgi.py
rename to docs/examples/python/configure_asgi.py
index 8081d747..8feb0ec2 100644
--- a/docs/examples/python/configure-asgi.py
+++ b/docs/examples/python/configure_asgi.py
@@ -10,11 +10,10 @@
from channels.routing import ProtocolTypeRouter, URLRouter # noqa: E402
+
from reactpy_django import REACTPY_WEBSOCKET_ROUTE # noqa: E402
-application = ProtocolTypeRouter(
- {
- "http": django_asgi_app,
- "websocket": URLRouter([REACTPY_WEBSOCKET_ROUTE]),
- }
-)
+application = ProtocolTypeRouter({
+ "http": django_asgi_app,
+ "websocket": URLRouter([REACTPY_WEBSOCKET_ROUTE]),
+})
diff --git a/docs/examples/python/configure-asgi-middleware.py b/docs/examples/python/configure_asgi_middleware.py
similarity index 60%
rename from docs/examples/python/configure-asgi-middleware.py
rename to docs/examples/python/configure_asgi_middleware.py
index 6df35a39..0c5a7214 100644
--- a/docs/examples/python/configure-asgi-middleware.py
+++ b/docs/examples/python/configure_asgi_middleware.py
@@ -1,5 +1,6 @@
# Broken load order, only used for linting
from channels.routing import ProtocolTypeRouter, URLRouter
+
from reactpy_django import REACTPY_WEBSOCKET_ROUTE
django_asgi_app = ""
@@ -8,9 +9,7 @@
# start
from channels.auth import AuthMiddlewareStack # noqa: E402
-application = ProtocolTypeRouter(
- {
- "http": django_asgi_app,
- "websocket": AuthMiddlewareStack(URLRouter([REACTPY_WEBSOCKET_ROUTE])),
- }
-)
+application = ProtocolTypeRouter({
+ "http": django_asgi_app,
+ "websocket": AuthMiddlewareStack(URLRouter([REACTPY_WEBSOCKET_ROUTE])),
+})
diff --git a/docs/examples/python/configure-channels-asgi-app.py b/docs/examples/python/configure_channels_asgi_app.py
similarity index 100%
rename from docs/examples/python/configure-channels-asgi-app.py
rename to docs/examples/python/configure_channels_asgi_app.py
diff --git a/docs/examples/python/configure-channels-installed-app.py b/docs/examples/python/configure_channels_installed_app.py
similarity index 100%
rename from docs/examples/python/configure-channels-installed-app.py
rename to docs/examples/python/configure_channels_installed_app.py
diff --git a/docs/examples/python/configure-installed-apps.py b/docs/examples/python/configure_installed_apps.py
similarity index 100%
rename from docs/examples/python/configure-installed-apps.py
rename to docs/examples/python/configure_installed_apps.py
diff --git a/docs/examples/python/configure-urls.py b/docs/examples/python/configure_urls.py
similarity index 100%
rename from docs/examples/python/configure-urls.py
rename to docs/examples/python/configure_urls.py
diff --git a/docs/examples/python/django-css.py b/docs/examples/python/django_css.py
similarity index 99%
rename from docs/examples/python/django-css.py
rename to docs/examples/python/django_css.py
index aeb4addb..c7f60881 100644
--- a/docs/examples/python/django-css.py
+++ b/docs/examples/python/django_css.py
@@ -1,4 +1,5 @@
from reactpy import component, html
+
from reactpy_django.components import django_css
diff --git a/docs/examples/python/django-css-external-link.py b/docs/examples/python/django_css_external_link.py
similarity index 53%
rename from docs/examples/python/django-css-external-link.py
rename to docs/examples/python/django_css_external_link.py
index ac1d0fba..28eb3fca 100644
--- a/docs/examples/python/django-css-external-link.py
+++ b/docs/examples/python/django_css_external_link.py
@@ -4,8 +4,6 @@
@component
def my_component():
return html.div(
- html.link(
- {"rel": "stylesheet", "href": "https://example.com/external-styles.css"}
- ),
+ html.link({"rel": "stylesheet", "href": "https://example.com/external-styles.css"}),
html.button("My Button!"),
)
diff --git a/docs/examples/python/django-css-local-link.py b/docs/examples/python/django_css_local_link.py
similarity index 100%
rename from docs/examples/python/django-css-local-link.py
rename to docs/examples/python/django_css_local_link.py
diff --git a/docs/examples/python/django_form.py b/docs/examples/python/django_form.py
new file mode 100644
index 00000000..51960db1
--- /dev/null
+++ b/docs/examples/python/django_form.py
@@ -0,0 +1,10 @@
+from reactpy import component, html
+
+from example.forms import MyForm
+from reactpy_django.components import django_form
+
+
+@component
+def basic_form():
+ children = [html.input({"type": "submit"})]
+ return django_form(MyForm, bottom_children=children)
diff --git a/docs/examples/python/django_form_bootstrap.py b/docs/examples/python/django_form_bootstrap.py
new file mode 100644
index 00000000..449e1cc4
--- /dev/null
+++ b/docs/examples/python/django_form_bootstrap.py
@@ -0,0 +1,9 @@
+from reactpy import component
+
+from example.forms import MyForm
+from reactpy_django.components import django_form
+
+
+@component
+def basic_form():
+ return django_form(MyForm, form_template="bootstrap_form.html")
diff --git a/docs/examples/python/django_form_class.py b/docs/examples/python/django_form_class.py
new file mode 100644
index 00000000..e556295e
--- /dev/null
+++ b/docs/examples/python/django_form_class.py
@@ -0,0 +1,5 @@
+from django import forms
+
+
+class MyForm(forms.Form):
+ username = forms.CharField(label="Username")
diff --git a/docs/examples/python/django_form_on_success.py b/docs/examples/python/django_form_on_success.py
new file mode 100644
index 00000000..d8b6927c
--- /dev/null
+++ b/docs/examples/python/django_form_on_success.py
@@ -0,0 +1,21 @@
+from reactpy import component, hooks, html
+from reactpy_router import navigate
+
+from example.forms import MyForm
+from reactpy_django.components import django_form
+from reactpy_django.types import FormEventData
+
+
+@component
+def basic_form():
+ submitted, set_submitted = hooks.use_state(False)
+
+ def on_submit(event: FormEventData):
+ """This function will be called when the form is successfully submitted."""
+ set_submitted(True)
+
+ if submitted:
+ return navigate("/homepage")
+
+ children = [html.input({"type": "submit"})]
+ return django_form(MyForm, on_success=on_submit, bottom_children=children)
diff --git a/docs/examples/python/django-js.py b/docs/examples/python/django_js.py
similarity index 99%
rename from docs/examples/python/django-js.py
rename to docs/examples/python/django_js.py
index b4af014c..37868184 100644
--- a/docs/examples/python/django-js.py
+++ b/docs/examples/python/django_js.py
@@ -1,4 +1,5 @@
from reactpy import component, html
+
from reactpy_django.components import django_js
diff --git a/docs/examples/python/django-js-local-script.py b/docs/examples/python/django_js_local_script.py
similarity index 100%
rename from docs/examples/python/django-js-local-script.py
rename to docs/examples/python/django_js_local_script.py
diff --git a/docs/examples/python/django-js-remote-script.py b/docs/examples/python/django_js_remote_script.py
similarity index 100%
rename from docs/examples/python/django-js-remote-script.py
rename to docs/examples/python/django_js_remote_script.py
diff --git a/docs/examples/python/django-query-postprocessor.py b/docs/examples/python/django_query_postprocessor.py
similarity index 99%
rename from docs/examples/python/django-query-postprocessor.py
rename to docs/examples/python/django_query_postprocessor.py
index da33c362..7bdc870c 100644
--- a/docs/examples/python/django-query-postprocessor.py
+++ b/docs/examples/python/django_query_postprocessor.py
@@ -1,5 +1,6 @@
-from example.models import TodoItem
from reactpy import component
+
+from example.models import TodoItem
from reactpy_django.hooks import use_query
from reactpy_django.utils import django_query_postprocessor
diff --git a/docs/examples/python/django-router.py b/docs/examples/python/django_router.py
similarity index 92%
rename from docs/examples/python/django-router.py
rename to docs/examples/python/django_router.py
index 5c845967..721eb939 100644
--- a/docs/examples/python/django-router.py
+++ b/docs/examples/python/django_router.py
@@ -1,7 +1,8 @@
from reactpy import component, html
-from reactpy_django.router import django_router
from reactpy_router import route
+from reactpy_django.router import django_router
+
@component
def my_component():
@@ -14,5 +15,5 @@ def my_component():
route("/router/string/
Create user interfaces from components
Whether you work on your own or with thousands of other developers, using React feels the same. It is @@ -94,9 +94,9 @@
You don't have to build your whole page in ReactPy. Add React to your existing HTML page, and render diff --git a/docs/overrides/home-code-examples/add-interactivity.py b/docs/overrides/homepage_examples/add_interactivity.py similarity index 74% rename from docs/overrides/home-code-examples/add-interactivity.py rename to docs/overrides/homepage_examples/add_interactivity.py index f29ba3c8..9a7bf76f 100644 --- a/docs/overrides/home-code-examples/add-interactivity.py +++ b/docs/overrides/homepage_examples/add_interactivity.py @@ -1,8 +1,9 @@ -# pylint: disable=assignment-from-no-return, unnecessary-lambda +# ruff: noqa: INP001 from reactpy import component, html, use_state -def filter_videos(*_, **__): ... +def filter_videos(*_, **__): + return [] def search_input(*_, **__): ... @@ -18,7 +19,7 @@ def searchable_video_list(videos): return html._( search_input( - {"onChange": lambda new_text: set_search_text(new_text)}, + {"onChange": lambda event: set_search_text(event["target"]["value"])}, value=search_text, ), video_list( diff --git a/docs/overrides/home-code-examples/add-interactivity-demo.html b/docs/overrides/homepage_examples/add_interactivity_demo.html similarity index 100% rename from docs/overrides/home-code-examples/add-interactivity-demo.html rename to docs/overrides/homepage_examples/add_interactivity_demo.html diff --git a/docs/overrides/home-code-examples/code-block.html b/docs/overrides/homepage_examples/code_block.html similarity index 100% rename from docs/overrides/home-code-examples/code-block.html rename to docs/overrides/homepage_examples/code_block.html diff --git a/docs/overrides/home-code-examples/create-user-interfaces.py b/docs/overrides/homepage_examples/create_user_interfaces.py similarity index 94% rename from docs/overrides/home-code-examples/create-user-interfaces.py rename to docs/overrides/homepage_examples/create_user_interfaces.py index 873b9d88..7878aa6b 100644 --- a/docs/overrides/home-code-examples/create-user-interfaces.py +++ b/docs/overrides/homepage_examples/create_user_interfaces.py @@ -1,3 +1,4 @@ +# ruff: noqa: INP001 from reactpy import component, html diff --git a/docs/overrides/home-code-examples/create-user-interfaces-demo.html b/docs/overrides/homepage_examples/create_user_interfaces_demo.html similarity index 100% rename from docs/overrides/home-code-examples/create-user-interfaces-demo.html rename to docs/overrides/homepage_examples/create_user_interfaces_demo.html diff --git a/docs/overrides/home-code-examples/write-components-with-python.py b/docs/overrides/homepage_examples/write_components_with_python.py similarity index 94% rename from docs/overrides/home-code-examples/write-components-with-python.py rename to docs/overrides/homepage_examples/write_components_with_python.py index 47e28b68..5993046c 100644 --- a/docs/overrides/home-code-examples/write-components-with-python.py +++ b/docs/overrides/homepage_examples/write_components_with_python.py @@ -1,3 +1,4 @@ +# ruff: noqa: INP001 from reactpy import component, html diff --git a/docs/overrides/home-code-examples/write-components-with-python-demo.html b/docs/overrides/homepage_examples/write_components_with_python_demo.html similarity index 100% rename from docs/overrides/home-code-examples/write-components-with-python-demo.html rename to docs/overrides/homepage_examples/write_components_with_python_demo.html diff --git a/docs/src/about/code.md b/docs/src/about/code.md deleted file mode 100644 index 81e49c51..00000000 --- a/docs/src/about/code.md +++ /dev/null @@ -1,85 +0,0 @@ -## Overview - -
- - You will need to set up a Python environment to develop ReactPy-Django. - -
- -!!! abstract "Note" - - Looking to contribute features that are not Django specific? - - Everything within the `reactpy-django` repository must be specific to Django integration. Check out the [ReactPy Core documentation](https://reactpy.dev/docs/about/contributor-guide.html) to contribute general features such as components, hooks, and events. - ---- - -## Creating an environment - -If you plan to make code changes to this repository, you will need to install the following dependencies first: - -- [Python 3.9+](https://www.python.org/downloads/) -- [Bun](https://bun.sh/) -- [Git](https://git-scm.com/downloads) - -Once done, you should clone this repository: - -```bash linenums="0" -git clone https://github.com/reactive-python/reactpy-django.git -cd reactpy-django -``` - -Then, by running the command below you can install the dependencies needed to run the ReactPy-Django development environment. - -```bash linenums="0" -pip install -r requirements.txt --upgrade --verbose -``` - -!!! warning "Pitfall" - - Some of our development dependencies require a C++ compiler, which is not installed by default on Windows. If you receive errors related to this during installation, follow the instructions in your console errors. - - Additionally, be aware that ReactPy-Django's JavaScript bundle is built within the following scenarios: - - 1. When `pip install` is run on the `reactpy-django` package. - 2. Every time `python manage.py ...` or `nox ...` is run - -## Running the full test suite - -!!! abstract "Note" - - This repository uses [Nox](https://nox.thea.codes/en/stable/) to run tests. For a full test of available scripts run `nox -l`. - -By running the command below you can run the full test suite: - -```bash linenums="0" -nox -t test -``` - -Or, if you want to run the tests in the background: - -```bash linenums="0" -nox -t test -- --headless -``` - -## Running Django tests - -If you want to only run our Django tests in your current environment, you can use the following command: - -```bash linenums="0" -cd tests -python manage.py test -``` - -## Running Django test web server - -If you want to manually run the Django test application, you can use the following command: - -```bash linenums="0" -cd tests -python manage.py runserver -``` - -## Creating a pull request - -{% include-markdown "../../includes/pr.md" %} diff --git a/docs/src/about/contributing.md b/docs/src/about/contributing.md new file mode 100644 index 00000000..06499c3e --- /dev/null +++ b/docs/src/about/contributing.md @@ -0,0 +1,94 @@ +## Overview + ++ + You will need to set up a Python environment to develop ReactPy-Django. + +
+ +!!! abstract "Note" + + Looking to contribute features that are not Django specific? + + Everything within the `reactpy-django` repository must be specific to Django integration. Check out the [ReactPy Core documentation](https://reactpy.dev/docs/about/contributor-guide.html) to contribute general features such as components, hooks, and events. + +--- + +## Creating a development environment + +If you plan to make code changes to this repository, you will need to install the following dependencies first: + +- [Git](https://git-scm.com/downloads) +- [Python 3.9+](https://www.python.org/downloads/) +- [Hatch](https://hatch.pypa.io/latest/) +- [Bun](https://bun.sh/) + +Once you finish installing these dependencies, you can clone this repository: + +```bash linenums="0" +git clone https://github.com/reactive-python/reactpy-django.git +cd reactpy-django +``` + +## Executing test environment commands + +By utilizing `hatch`, the following commands are available to manage the development environment. + +### Tests + +| Command | Description | +| --- | --- | +| `hatch test` | Run Python tests using the current environment's Python version | +| `hatch test --all` | Run tests using all compatible Python versions | +| `hatch test --python 3.9` | Run tests using a specific Python version | +| `hatch test --include "django=5.1"` | Run tests using a specific Django version | +| `hatch test -k test_object_in_templatetag` | Run only a specific test | +| `hatch test --ds test_app.settings_multi_db` | Run tests with a specific Django settings file | +| `hatch run django:runserver` | Manually run the Django development server without running tests | + +??? question "What other arguments are available to me?" + + The `hatch test` command is a wrapper for `pytest`. Hatch "intercepts" a handful of arguments, which can be previewed by typing `hatch test --help`. + + Any additional arguments in the `test` command are provided directly to pytest. See the [pytest documentation](https://docs.pytest.org/en/stable/reference/reference.html#command-line-flags) for what additional arguments are available. + +### Linting and Formatting + +| Command | Description | +| --- | --- | +| `hatch fmt` | Run all linters and formatters | +| `hatch fmt --check` | Run all linters and formatters, but do not save fixes to the disk | +| `hatch fmt --linter` | Run only linters | +| `hatch fmt --formatter` | Run only formatters | +| `hatch run javascript:check` | Run the JavaScript linter/formatter | +| `hatch run javascript:fix` | Run the JavaScript linter/formatter and write fixes to disk | +| `hatch run python:type_check` | Run the Python type checker | + +??? tip "Configure your IDE for linting" + + This repository uses `hatch fmt` for linting and formatting, which is a [modestly customized](https://hatch.pypa.io/latest/config/internal/static-analysis/#default-settings) version of [`ruff`](https://github.com/astral-sh/ruff). + + You can install `ruff` as a plugin to your preferred code editor to create a similar environment. + +### Documentation + +| Command | Description | +| --- | --- | +| `hatch run docs:serve` | Start the [`mkdocs`](https://www.mkdocs.org/) server to view documentation locally | +| `hatch run docs:build` | Build the documentation | +| `hatch run docs:linkcheck` | Check for broken links in the documentation | +| `hatch fmt docs --check` | Run linter on code examples in the documentation | + +### Environment Management + +| Command | Description | +| --- | --- | +| `hatch build --clean` | Build the package from source | +| `hatch env prune` | Delete all virtual environments created by `hatch` | +| `hatch python install 3.12` | Install a specific Python version to your system | + +??? tip "Check out Hatch for all available commands!" + + This documentation only covers commonly used commands. + + You can type `hatch --help` to see all available commands. diff --git a/docs/src/about/docs.md b/docs/src/about/docs.md deleted file mode 100644 index 712570ec..00000000 --- a/docs/src/about/docs.md +++ /dev/null @@ -1,45 +0,0 @@ -## Overview - -- -You will need to set up a Python environment to create, test, and preview docs changes. - -
- ---- - -## Modifying Docs - -If you plan to make changes to this documentation, you will need to install the following dependencies first: - -- [Python 3.9+](https://www.python.org/downloads/) -- [Git](https://git-scm.com/downloads) - -Once done, you should clone this repository: - -```bash linenums="0" -git clone https://github.com/reactive-python/reactpy-django.git -cd reactpy-django -``` - -Then, by running the command below you can: - -- Install an editable version of the documentation -- Self-host a test server for the documentation - -```bash linenums="0" -pip install -r requirements.txt --upgrade -``` - -Finally, to verify that everything is working properly, you can manually run the docs preview web server. - -```bash linenums="0" -cd docs -mkdocs serve -``` - -Navigate to [`http://127.0.0.1:8000`](http://127.0.0.1:8000) to view a preview of the documentation. - -## GitHub Pull Request - -{% include-markdown "../../includes/pr.md" %} diff --git a/docs/src/assets/img/add-interactivity.png b/docs/src/assets/img/add-interactivity.png index 009b52ac..c3243190 100644 Binary files a/docs/src/assets/img/add-interactivity.png and b/docs/src/assets/img/add-interactivity.png differ diff --git a/docs/src/dictionary.txt b/docs/src/dictionary.txt index 14aa7a61..d2ff722d 100644 --- a/docs/src/dictionary.txt +++ b/docs/src/dictionary.txt @@ -43,3 +43,9 @@ unstyled WebSocket WebSockets whitespace +pytest +linter +linters +linting +formatters +bootstrap_form diff --git a/docs/src/learn/add-reactpy-to-a-django-project.md b/docs/src/learn/add-reactpy-to-a-django-project.md index 0bf919e2..371893e1 100644 --- a/docs/src/learn/add-reactpy-to-a-django-project.md +++ b/docs/src/learn/add-reactpy-to-a-django-project.md @@ -29,7 +29,7 @@ Add `#!python "reactpy_django"` to [`INSTALLED_APPS`](https://docs.djangoproject === "settings.py" ```python - {% include "../../examples/python/configure-installed-apps.py" %} + {% include "../../examples/python/configure_installed_apps.py" %} ``` ??? warning "Enable ASGI and Django Channels (Required)" @@ -42,13 +42,13 @@ Add `#!python "reactpy_django"` to [`INSTALLED_APPS`](https://docs.djangoproject 2. Add `#!python "daphne"` to `#!python INSTALLED_APPS`. ```python linenums="0" - {% include "../../examples/python/configure-channels-installed-app.py" %} + {% include "../../examples/python/configure_channels_installed_app.py" %} ``` 3. Set your `#!python ASGI_APPLICATION` variable. ```python linenums="0" - {% include "../../examples/python/configure-channels-asgi-app.py" %} + {% include "../../examples/python/configure_channels_asgi_app.py" %} ``` ??? info "Configure ReactPy settings (Optional)" @@ -64,7 +64,7 @@ Add ReactPy HTTP paths to your `#!python urlpatterns` in your [`urls.py`](https: === "urls.py" ```python - {% include "../../examples/python/configure-urls.py" %} + {% include "../../examples/python/configure_urls.py" %} ``` ## Step 4: Configure `asgi.py` @@ -74,7 +74,7 @@ Register ReactPy's WebSocket using `#!python REACTPY_WEBSOCKET_ROUTE` in your [` === "asgi.py" ```python - {% include "../../examples/python/configure-asgi.py" %} + {% include "../../examples/python/configure_asgi.py" %} ``` ??? info "Add `#!python AuthMiddlewareStack` (Optional)" @@ -87,9 +87,7 @@ Register ReactPy's WebSocket using `#!python REACTPY_WEBSOCKET_ROUTE` in your [` In these situations will need to ensure you are using `#!python AuthMiddlewareStack`. - ```python linenums="0" - {% include "../../examples/python/configure-asgi-middleware.py" start="# start" %} - ``` + {% include "../../includes/auth-middleware-stack.md" %} ??? question "Where is my `asgi.py`?" diff --git a/docs/src/learn/your-first-component.md b/docs/src/learn/your-first-component.md index 85af4109..e3be5da4 100644 --- a/docs/src/learn/your-first-component.md +++ b/docs/src/learn/your-first-component.md @@ -8,7 +8,7 @@ Components are one of the core concepts of ReactPy. They are the foundation upon !!! abstract "Note" - If you have reached this point, you should have already [installed ReactPy-Django](../learn/add-reactpy-to-a-django-project.md) through the previous steps. + If you have reached this point, you should have already [installed ReactPy-Django](./add-reactpy-to-a-django-project.md) through the previous steps. --- @@ -68,7 +68,7 @@ Additionally, you can pass in `#!python args` and `#!python kwargs` into your co ???+ tip "Components are automatically registered!" - ReactPy-Django will automatically register any component that is referenced in a Django HTML template. This means you [typically](../reference/utils.md#register-component) do not need to manually register components in your **Django app**. + ReactPy-Django will automatically register any component that is referenced in a Django HTML template. This means you typically do not need to [manually register](../reference/utils.md#register-component) components in your **Django app**. Please note that this HTML template must be properly stored within a registered Django app. ReactPy-Django will output a console log message containing all detected components when the server starts up. @@ -87,7 +87,7 @@ Within your **Django app**'s `views.py` file, you will need to [create a view fu === "views.py" ```python - {% include "../../examples/python/example/views.py" %} + {% include "../../examples/python/first_view.py" %} ``` We will add this new view into your [`urls.py`](https://docs.djangoproject.com/en/stable/intro/tutorial01/#write-your-first-view) and define what URL it should be accessible at. @@ -95,7 +95,7 @@ We will add this new view into your [`urls.py`](https://docs.djangoproject.com/e === "urls.py" ```python - {% include "../../examples/python/example/urls.py" %} + {% include "../../examples/python/first_urls.py" %} ``` ??? question "Which urls.py do I add my views to?" diff --git a/docs/src/reference/components.md b/docs/src/reference/components.md index 943b76c0..448af463 100644 --- a/docs/src/reference/components.md +++ b/docs/src/reference/components.md @@ -12,26 +12,26 @@ We supply some pre-designed that components can be used to help simplify develop This allows you to embedded any number of client-side PyScript components within traditional ReactPy components. -{% include-markdown "../reference/template-tag.md" start="" end="" %} +{% include-markdown "./template-tag.md" start="" end="" %} -{% include-markdown "../reference/template-tag.md" start="" end="" %} +{% include-markdown "./template-tag.md" start="" end="" %} === "components.py" ```python - {% include "../../examples/python/pyscript-ssr-parent.py" %} + {% include "../../examples/python/pyscript_ssr_parent.py" %} ``` === "root.py" ```python - {% include "../../examples/python/pyscript-ssr-child.py" %} + {% include "../../examples/python/pyscript_ssr_child.py" %} ``` === "my_template.html" ```jinja - {% include "../../examples/html/pyscript-ssr-parent.html" %} + {% include "../../examples/html/pyscript_ssr_parent.html" %} ``` ??? example "See Interface" @@ -53,31 +53,33 @@ This allows you to embedded any number of client-side PyScript components within === "my_template.html" ```jinja - {% include "../../examples/html/pyscript-setup.html" %} + {% include "../../examples/html/pyscript_setup.html" %} ``` -{% include-markdown "../reference/template-tag.md" start="" end="" %} +{% include-markdown "./template-tag.md" start="" end="" %} -{% include-markdown "../reference/template-tag.md" start="" end="" trailing-newlines=false preserve-includer-indent=false %} +{% include-markdown "./template-tag.md" start="" end="" %} + +{% include-markdown "./template-tag.md" start="" end="" trailing-newlines=false preserve-includer-indent=false %} === "components.py" ```python - {% include "../../examples/python/pyscript-component-multiple-files-root.py" %} + {% include "../../examples/python/pyscript_component_multiple_files_root.py" %} ``` === "root.py" ```python - {% include "../../examples/python/pyscript-multiple-files-root.py" %} + {% include "../../examples/python/pyscript_multiple_files_root.py" %} ``` === "child.py" ```python - {% include "../../examples/python/pyscript-multiple-files-child.py" %} + {% include "../../examples/python/pyscript_multiple_files_child.py" %} ``` ??? question "How do I display something while the component is loading?" @@ -89,7 +91,7 @@ This allows you to embedded any number of client-side PyScript components within === "components.py" ```python - {% include "../../examples/python/pyscript-component-initial-object.py" %} + {% include "../../examples/python/pyscript_component_initial_object.py" %} ``` However, you can also use a string containing raw HTML. @@ -97,7 +99,7 @@ This allows you to embedded any number of client-side PyScript components within === "components.py" ```python - {% include "../../examples/python/pyscript-component-initial-string.py" %} + {% include "../../examples/python/pyscript_component_initial_string.py" %} ``` ??? question "Can I use a different name for my root component?" @@ -107,13 +109,13 @@ This allows you to embedded any number of client-side PyScript components within === "components.py" ```python - {% include "../../examples/python/pyscript-component-root.py" %} + {% include "../../examples/python/pyscript_component_root.py" %} ``` === "main.py" ```python - {% include "../../examples/python/pyscript-root.py" %} + {% include "../../examples/python/pyscript_root.py" %} ``` --- @@ -156,11 +158,11 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. ??? info "Existing limitations" - There are currently several limitations of using `#!python view_to_component` that may be resolved in a future version. + There are currently several limitations of using `#!python view_to_component` that will be [resolved in a future version](https://github.com/reactive-python/reactpy-django/issues/269). - Requires manual intervention to change HTTP methods to anything other than `GET`. - ReactPy events cannot conveniently be attached to converted view HTML. - - Has no option to automatically intercept local anchor link (such as `#!html `) click events. + - Has no option to automatically intercept click events from hyperlinks (such as `#!html `). ??? question "How do I use this for Class Based Views?" @@ -171,7 +173,7 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. === "components.py" ```python - {% include "../../examples/python/vtc-cbv.py" %} + {% include "../../examples/python/vtc_cbv.py" %} ``` === "views.py" @@ -187,7 +189,7 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. === "components.py" ```python - {% include "../../examples/python/vtc-args.py" %} + {% include "../../examples/python/vtc_args.py" %} ``` === "views.py" @@ -215,7 +217,7 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. === "components.py" ```python - {% include "../../examples/python/vtc-strict-parsing.py" %} + {% include "../../examples/python/vtc_strict_parsing.py" %} ``` === "views.py" @@ -237,7 +239,7 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. === "components.py" ```python - {% include "../../examples/python/vtc-transforms.py" %} + {% include "../../examples/python/vtc_transforms.py" %} ``` === "views.py" @@ -292,12 +294,12 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. ??? info "Existing limitations" - There are currently several limitations of using `#!python view_to_iframe` that may be resolved in a future version. + There are currently several limitations of using `#!python view_to_iframe` which may be [resolved in a future version](https://github.com/reactive-python/reactpy-django/issues/268). - No built-in method of signalling events back to the parent component. - - All provided `#!python *args` and `#!python *kwargs` must be serializable values, since they are encoded into the URL. + - All provided `#!python args` and `#!python kwargs` must be serializable values, since they are encoded into the URL. - The `#!python iframe` will always load **after** the parent component. - - CSS styling for `#!python iframe` elements tends to be awkward/difficult. + - CSS styling for `#!python iframe` elements tends to be awkward. ??? question "How do I use this for Class Based Views?" @@ -308,7 +310,7 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. === "components.py" ```python - {% include "../../examples/python/vti-cbv.py" %} + {% include "../../examples/python/vti_cbv.py" %} ``` === "views.py" @@ -332,7 +334,7 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. === "components.py" ```python - {% include "../../examples/python/vti-args.py" %} + {% include "../../examples/python/vti_args.py" %} ``` === "views.py" @@ -364,7 +366,7 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. === "components.py" ```python - {% include "../../examples/python/vti-extra-props.py" %} + {% include "../../examples/python/vti_extra_props.py" %} ``` === "views.py" @@ -381,6 +383,104 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject. --- +## Django Form + +Automatically convert a Django form into a ReactPy component. + +Compatible with both [standard Django forms](https://docs.djangoproject.com/en/stable/topics/forms/#building-a-form) and [ModelForms](https://docs.djangoproject.com/en/stable/topics/forms/modelforms/). + +=== "components.py" + + ```python + {% include "../../examples/python/django_form.py" %} + ``` + +=== "forms.py" + + ```python + {% include "../../examples/python/django_form_class.py" %} + ``` + +??? example "See Interface" + + **Parameters** + + | Name | Type | Description | Default | + | --- | --- | --- | --- | + | `#!python form` | `#!python type[Form | ModelForm]` | The form to convert. | N/A | + | `#!python on_success` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when the form is successfully submitted. | `#!python None` | + | `#!python on_error` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when the form submission fails. | `#!python None` | + | `#!python on_receive_data` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called before newly submitted form data is rendered. | `#!python None` | + | `#!python on_change` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when a form field is modified by the user. | `#!python None` | + | `#!python auto_save` | `#!python bool` | If `#!python True`, the form will automatically call `#!python save` on successful submission of a `#!python ModelForm`. This has no effect on regular `#!python Form` instances. | `#!python True` | + | `#!python extra_props` | `#!python dict[str, Any] | None` | Additional properties to add to the `#!html