Changelog
Changelog
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
Added¶
- Client-side Python components can now be rendered via the new
{% pyscript_component %}
template tag- You must first call the
{% pyscript_setup %}
template tag to load PyScript dependencies
- You must first call the
- Client-side components can be embedded into existing server-side components via
reactpy_django.components.pyscript_component
. - Tired of writing JavaScript? You can now write PyScript code that runs directly within client browser via the
reactpy_django.html.pyscript
element.- This is a viable substitution for most JavaScript code.
Changed¶
-
New syntax for
use_query
anduse_mutation
hooks. Here's a quick comparison of the changes:1 +-->
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
- Nothing (yet)!
4.0.0¶
Added¶
- Client-side Python components can now be rendered via the new
{% pyscript_component %}
template tag- You must first call the
{% pyscript_setup %}
template tag to load PyScript dependencies
- You must first call the
- Client-side components can be embedded into existing server-side components via
reactpy_django.components.pyscript_component
. - Tired of writing JavaScript? You can now write PyScript code that runs directly within client browser via the
reactpy_django.html.pyscript
element.- This is a viable substitution for most JavaScript code.
Changed¶
-
New syntax for
use_query
anduse_mutation
hooks. Here's a quick comparison of the changes:1 2 3 4 diff --git a/develop/search/search_index.json b/develop/search/search_index.json index bbfc8c22..840d2b39 100644 --- a/develop/search/search_index.json +++ b/develop/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"about/changelog/","title":"Changelog","text":"
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
"},{"location":"about/changelog/#unreleased","title":"Unreleased","text":""},{"location":"about/changelog/#added","title":"Added","text":"- Client-side Python components can now be rendered via the new
{% pyscript_component %}
template tag- You must first call the
{% pyscript_setup %}
template tag to load PyScript dependencies
- You must first call the
- Client-side components can be embedded into existing server-side components via
reactpy_django.components.pyscript_component
. - Tired of writing JavaScript? You can now write PyScript code that runs directly within client browser via the
reactpy_django.html.pyscript
element.- This is a viable substitution for most JavaScript code.
-
New syntax for
use_query
anduse_mutation
hooks. Here's a quick comparison of the changes:query = use_query(QueryOptions(thread_sensitive=True), get_items, foo=\"bar\") # Old\nquery = use_query(get_items, {\"foo\":\"bar\"}, thread_sensitive=True) # New\n\nmutation = use_mutation(MutationOptions(thread_sensitive=True), remove_item) # Old\nmutation = use_mutation(remove_item, thread_sensitive=True) # New\n
QueryOptions
andMutationOptions
have been removed. The value contained within these objects are now passed directly into the hook.
- Resolved a bug where Django-ReactPy would not properly detect
settings.py:DEBUG
.
- Python 3.12 compatibility
- Built-in cross-process communication mechanism via the
reactpy_django.hooks.use_channel_layer
hook. - Access to the root component's
id
via thereactpy_django.hooks.use_root_id
hook. - More robust control over ReactPy clean up tasks!
settings.py:REACTPY_CLEAN_INTERVAL
to control how often ReactPy automatically performs cleaning tasks.settings.py:REACTPY_CLEAN_SESSIONS
to control whether ReactPy should clean up expired sessions during automatic cleanups.settings.py:REACTPY_CLEAN_USER_DATA
to control whether ReactPy should clean up orphaned user data during automatic cleanups.python manage.py clean_reactpy
command to manually perform ReactPy clean up tasks.
- Simplified code for cascading deletion of user data.
- An \"offline component\" can now be displayed when the client disconnects from the server.
- URL router now supports a
*
wildcard to create default routes.
- Built-in Single Page Application (SPA) support!
reactpy_django.router.django_router
can be used to render your Django application as a SPA.
- SEO compatible rendering!
settings.py:REACTPY_PRERENDER
can be set toTrue
to make components pre-render by default.- Or, you can enable it on individual components via the template tag:
{% component \"...\" prerender=\"True\" %}
.
- New
view_to_iframe
feature!reactpy_django.components.view_to_iframe
uses an<iframe>
to render a Django view.reactpy_django.utils.register_iframe
tells ReactPy which viewsview_to_iframe
can use.
- New Django
User
related features!reactpy_django.hooks.use_user
can be used to access the current user.reactpy_django.hooks.use_user_data
provides a simplified interface for storing user key-value data.reactpy_django.decorators.user_passes_test
is inspired by the equivalent Django decorator, but ours works with ReactPy components.settings.py:REACTPY_AUTO_RELOGIN
will cause component WebSocket connections to automatically re-login users that are already authenticated. This is useful to continuously updatelast_login
timestamps and refresh the Django login session.
- Renamed undocumented utility function
ComponentPreloader
toRootComponentFinder
. - It is now recommended to call
as_view()
when usingview_to_component
orview_to_iframe
with Class Based Views. - For thread safety,
thread_sensitive=True
has been enabled in allsync_to_async
functions where ORM queries are possible. reactpy_django.hooks.use_mutation
now has a__call__
method. So rather than writingmy_mutation.execute(...)
, you can now writemy_mutation(...)
.
- The
compatibility
argument onreactpy_django.components.view_to_component
is deprecated.- Use
view_to_iframe
as a replacement.
- Use
reactpy_django.components.view_to_component
usage as a decorator is deprecated.- Check the docs on how to use
view_to_component
as a function instead.
- Check the docs on how to use
reactpy_django.decorators.auth_required
is deprecated.- Use
reactpy_django.decorators.user_passes_test
instead. - An equivalent to
auth_required
's default is@user_passes_test(lambda user: user.is_active)
.
- Use
- Fixed a bug where exception stacks would not print on failed component renders.
- Warning W018 (
Suspicious position of 'reactpy_django' in INSTALLED_APPS
) has been added.
- The default postprocessor can now disabled by setting
REACTPY_DEFAULT_QUERY_POSTPROCESSOR
toNone
. - Massive overhaul of docs styling.
- More customization for reconnection behavior through new settings!
REACTPY_RECONNECT_INTERVAL
REACTPY_RECONNECT_MAX_INTERVAL
REACTPY_RECONNECT_MAX_RETRIES
REACTPY_RECONNECT_BACKOFF_MULTIPLIER
- ReactPy-Django docs are now version controlled via mike!
- Bumped the minimum ReactPy version to
1.0.2
. - Prettier WebSocket URLs for components that do not have sessions.
- Template tag will now only validate
args
/kwargs
ifsettings.py:DEBUG
is enabled. - Bumped the minimum
@reactpy/client
version to0.3.1
- Use TypeScript instead of JavaScript for this repository.
- Bumped the minimum Django version to
4.2
.
ReactPy-Django will continue bumping minimum Django requirements to versions that increase async support.
This \"latest-only\" trend will continue until Django has all async features that ReactPy benefits from. After this point, ReactPy-Django will begin supporting all maintained Django versions.
"},{"location":"about/changelog/#removed_1","title":"Removed","text":"settings.py:REACTPY_RECONNECT_MAX
is removed. See the docs for the newREACTPY_RECONNECT_*
settings.
- Distributed Computing: ReactPy components can now optionally be rendered by a completely separate server!
REACTPY_DEFAULT_HOSTS
setting can round-robin a list of ReactPy rendering hosts.host
argument has been added to thecomponent
template tag to force components to render on a specific host.
reactpy_django.utils.register_component
function can manually register root components.- Useful if you have dedicated ReactPy rendering application(s) that do not use HTML templates.
- ReactPy will now provide a warning if your HTTP URLs are not on the same prefix as your WebSockets.
- Cleaner logging output for auto-detected ReactPy root components.
reactpy_django.REACTPY_WEBSOCKET_PATH
is deprecated. The identical replacement isREACTPY_WEBSOCKET_ROUTE
.settings.py:REACTPY_WEBSOCKET_URL
is deprecated. The similar replacement isREACTPY_URL_PREFIX
.
- Warning W007 (
REACTPY_WEBSOCKET_URL doesn't end with a slash
) has been removed. ReactPy now automatically handles slashes. - Warning W008 (
REACTPY_WEBSOCKET_URL doesn't start with an alphanumeric character
) has been removed. ReactPy now automatically handles this scenario. - Error E009 (
channels is not in settings.py:INSTALLED_APPS
) has been removed. Newer versions ofchannels
do not require installation viaINSTALLED_APPS
to receive an ASGI web server.
- ReactPy WebSocket will now decode messages via
orjson
resulting in an ~6% overall performance improvement. - Built-in
asyncio
event loops are now patched vianest_asyncio
, resulting in an ~10% overall performance improvement. This has no performance impact if you are running your web server withuvloop
.
- Fix bug where
REACTPY_WEBSOCKET_URL
always generates a warning if unset. - Fixed bug on Windows where
assert f is self._write_fut
would be raised byuvicorn
whenREACTPY_BACKHAUL_THREAD = True
. - Fixed bug on Windows where rendering behavior would be jittery with
daphne
whenREACTPY_BACKHAUL_THREAD = True
.
- Additional system checks for ReactPy misconfigurations.
REACTPY_BACKHAUL_THREAD
now defaults toFalse
.
- Added system checks for a variety of common ReactPy misconfigurations.
REACTPY_BACKHAUL_THREAD
setting to enable/disable threading behavior.
- If using
settings.py:REACTPY_DATABASE
,reactpy_django.database.Router
must now be registered insettings.py:DATABASE_ROUTERS
. - By default, ReactPy will now use a backhaul thread to increase performance.
- Minimum Python version required is now
3.9
- A thread-safe cache is no longer required.
- Template tag exception details are now rendered on the webpage when
settings.py:DEBUG
is enabled.
- Prevent exceptions within the
component
template tag from causing the whole template to fail to render.
- Added warning if poor system/cache/database performance is detected while in
DEBUG
mode. - Added
REACTPY_AUTH_BACKEND
setting to allow for custom authentication backends.
- Using
SessionMiddlewareStack
is now optional. - Using
AuthMiddlewareStack
is now optional.
use_query
now supports async functions.use_mutation
now supports async functions.reactpy_django.types.QueryOptions.thread_sensitive
option to customize how sync queries are executed.reactpy_django.hooks.use_mutation
now acceptsreactpy_django.types.MutationOptions
option to customize how mutations are executed.
- The
mutate
argument onreactpy_django.hooks.use_mutation
has been renamed tomutation
.
- Fix bug where ReactPy utilizes Django's default cache timeout, which can prematurely expire the component cache.
reactpy-django
database entries are no longer cleaned during Django application startup. Instead, it will occur on webpage loads ifREACTPY_RECONNECT_MAX
seconds has elapsed since the last cleaning.
django-idom
has been renamed toreactpy-django
! Please note that all references to the wordidom
in your code should be changed toreactpy
. See the docs for more details.
This is Django-IDOM's biggest update yet!
To upgrade from previous version you will need to...
- Install
django-idom >= 3.0.0
- Run
idom rewrite-keys <DIR>
andidom rewrite-camel-case-props <DIR>
to update youridom.html.*
calls to the new syntax - Run
python manage.py migrate
to create the new Django-IDOM database entries
- The
idom
client will automatically configure itself to debug mode depending onsettings.py:DEBUG
. use_connection
hook for returning the browser's activeConnection
.IDOM_CACHE
is now configurable withinsettings.py
to whatever cache name you wish.
- It is now mandatory to run
manage.py migrate
after installing IDOM. - Bumped the minimum IDOM version to 1.0.0. Due to IDOM 1.0.0,
idom.html.*
...- HTML properties can now be
snake_case
. For exampleclassName
now becomesclass_name
. key=...
is now declared within the propsdict
(rather than as akwarg
).
- HTML properties can now be
- The
component
template tag now supports both positional and keyword arguments. - The
component
template tag now supports non-serializable arguments. IDOM_WS_MAX_RECONNECT_TIMEOUT
setting has been renamed toIDOM_RECONNECT_MAX
.
django_idom.hooks.use_websocket
has been removed. The similar replacement isdjango_idom.hooks.use_connection
.django_idom.types.IdomWebsocket
has been removed. The similar replacement isdjango_idom.types.Connection
.settings.py:CACHE['idom']
is no longer used by default. The name of the cache back-end must now be specified with theIDOM_CACHE
setting.
view_to_component
will now retain the contents of a<head>
tag when rendering.- React client is now set to
production
rather thandevelopment
. use_query
will now utilizefield.related_name
when postprocessing many-to-one relationships.
- Fixed a potential method of component template tag argument spoofing.
- Exception information will no longer be displayed on the page, based on the value of
settings.py:DEBUG
.
- Fixed bug where
use_query
would not recursively fetch many-to-one relationships. - IDOM preloader will now print out the exception stack when failing to import a module.
- Add
options: QueryOptions
parameter touse_query
to allow for configuration of this hook.
- By default,
use_query
will recursively prefetch all many-to-many or many-to-one relationships to preventSynchronousOnlyOperation
exceptions.
django_idom.hooks._fetch_lazy_fields
has been deleted. The equivalent replacement isdjango_idom.utils.django_query_postprocessor
.
- Minimum
channels
version is now4.0.0
.
- Change type hint on
view_to_component
callable to haverequest
argument be optional. - Change type hint on
view_to_component
to represent it as a decorator with parenthesis (such as@view_to_component(compatibility=True)
)
- Add note to docs about potential information exposure via
view_to_component
when usingcompatibility=True
.
- Ability to use
key=...
parameter on all prefabricated components.
use_origin
hook for returning the browser'slocation.origin
.
view_to_component
now returns aCallable
, instead of directly returning aComponent
. Check the docs for new usage info.use_mutation
anduse_query
will now log any query failures.
- Allow
use_mutation
to haverefetch=None
, as the docs suggest is possible. use_query
will now prefetch all fields to preventSynchronousOnlyOperation
exceptions.view_to_component
,django_css
, anddjango_js
type hints will now display like normal functions.- IDOM preloader no longer attempts to parse commented out IDOM components.
- Tests are now fully functional on Windows
auth_required
decorator to prevent your components from rendering to unauthenticated users.use_query
hook for fetching database values.use_mutation
hook for modifying database values.view_to_component
utility to convert legacy Django views to IDOM components.
- Bumped the minimum IDOM version to 0.40.2
- Testing suite now uses
playwright
instead ofselenium
- IDOM preloader is no longer sensitive to whitespace within template tags.
django_css
anddjango_js
components to defer loading CSS & JS files until needed.
- Bumped the minimum IDOM version to 0.39.0
- Django specific hooks!
use_websocket
,use_scope
, anduse_location
are now available within thedjango_idom.hooks
module. - Documentation has been placed into a formal docs webpage.
- Logging for when a component fails to import, or if no components were found within Django.
idom_component
template tag has been renamed tocomponent
- Bumped the minimum IDOM version to 0.38.0
websocket
parameter for components has been removed. Functionally, it is replaced withdjango_idom.hooks.use_websocket
.
- Bumped the minimum IDOM version to 0.37.2
- ModuleNotFoundError: No module named
idom.core.proto
caused by IDOM 0.37.2
- Bumped the minimum IDOM version to 0.37.1
- Bumped the minimum IDOM version to 0.36.3
- Ability to declare the HTML class of the top-level component
div
name = ...
parameter to IDOM HTTP paths for use withdjango.urls.reverse()
- Cache versioning to automatically invalidate old web module files from the cache back-end
- Automatic pre-population of the IDOM component registry
- Type hinting for
IdomWebsocket
- Fetching web modules from disk and/or cache is now fully async
- Static files are now contained within a
django_idom/
parent folder - Upgraded IDOM to version
0.36.0
- Minimum Django version required is now
4.0
- Minimum Python version required is now
3.8
IDOM_WEB_MODULES_PATH
has been replaced with Djangoinclude(...)
IDOM_WS_MAX_RECONNECT_DELAY
has been renamed toIDOM_WS_MAX_RECONNECT_TIMEOUT
idom_web_modules
cache back-end has been renamed toidom
- Increase test timeout values to prevent false positives
- Windows compatibility for building Django-IDOM
- Fixed potential directory traversal attack on the IDOM web modules URL
- Support for IDOM within the Django
You will need to set up a Python environment to develop ReactPy-Django.
Note
Looking to contribute features that are not Django specific?
Everything within the
"},{"location":"about/code/#creating-an-environment","title":"Creating an environment","text":"reactpy-django
repository must be specific to Django integration. Check out the ReactPy Core documentation to contribute general features such as components, hooks, and events.If you plan to make code changes to this repository, you will need to install the following dependencies first:
- Python 3.9+
- Git
Once done, you should clone this repository:
git clone https://github.com/reactive-python/reactpy-django.git\ncd reactpy-django\n
Then, by running the command below you can install the dependencies needed to run the ReactPy-Django development environment.
pip install -r requirements.txt --upgrade --verbose\n
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:
- When
pip install
is run on thereactpy-django
package. - Every time
python manage.py ...
ornox ...
is run
Note
This repository uses Nox 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:
nox -t test\n
Or, if you want to run the tests in the background:
"},{"location":"about/code/#running-django-tests","title":"Running Django tests","text":"nox -t test -- --headless\n
If you want to only run our Django tests in your current environment, you can use the following command:
"},{"location":"about/code/#running-django-test-web-server","title":"Running Django test web server","text":"cd tests\npython manage.py test\n
If you want to manually run the Django test application, you can use the following command:
"},{"location":"about/code/#creating-a-pull-request","title":"Creating a pull request","text":"cd tests\npython manage.py runserver\n
Now, you can create/modify the ReactPy-Django source code, and Pull Request (PR) your changes to our GitHub repository.
To learn how to create GitHub PRs, click here.
"},{"location":"about/docs/","title":"Docs","text":""},{"location":"about/docs/#overview","title":"Overview","text":"You will need to set up a Python environment to create, test, and preview docs changes.
"},{"location":"about/docs/#modifying-docs","title":"Modifying Docs","text":"If you plan to make changes to this documentation, you will need to install the following dependencies first:
- Python 3.9+
- Git
Once done, you should clone this repository:
git clone https://github.com/reactive-python/reactpy-django.git\ncd reactpy-django\n
Then, by running the command below you can:
- Install an editable version of the documentation
- Self-host a test server for the documentation
pip install -r requirements.txt --upgrade\n
Finally, to verify that everything is working properly, you can manually run the docs preview web server.
cd docs\nmkdocs serve\n
Navigate to
"},{"location":"about/docs/#github-pull-request","title":"GitHub Pull Request","text":"http://127.0.0.1:8000
to view a preview of the documentation.Now, you can create/modify the ReactPy-Django source code, and Pull Request (PR) your changes to our GitHub repository.
To learn how to create GitHub PRs, click here.
"},{"location":"about/license/","title":"License","text":""},{"location":"about/license/#the-mit-license-mit","title":"The MIT License (MIT)","text":""},{"location":"about/license/#copyright-c-reactive-python-and-affiliates","title":"Copyright (c) Reactive Python and affiliates.","text":"Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"},{"location":"learn/add-reactpy-to-a-django-project/","title":"Add ReactPy to a Django Project","text":""},{"location":"learn/add-reactpy-to-a-django-project/#overview","title":"Overview","text":"If you want to add some interactivity to your existing Django project, you don't have to rewrite it in ReactPy. Use ReactPy-Django to add ReactPy to your existing stack, and render interactive components anywhere.
Note
These docs assumes you have already created a Django project, which involves creating and installing at least one Django app.
If do not have a Django project, check out this 9 minute YouTube tutorial created by IDG TECHtalk.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-1-install-from-pypi","title":"Step 1: Install from PyPI","text":"Run the following command to install
reactpy-django
in your Python environment.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-2-configure-settingspy","title":"Step 2: Configurepip install reactpy-django\n
settings.py
","text":"Add
settings.py\"reactpy_django\"
toINSTALLED_APPS
in yoursettings.py
file.
Enable ASGI and Django Channels (Required)INSTALLED_APPS = [\n ...,\n \"reactpy_django\",\n]\n
ReactPy-Django requires Django ASGI and Django Channels WebSockets.
If you have not enabled ASGI on your Django project yet, here is a summary of the
django
andchannels
installation docs:- Install
channels[daphne]
-
Add
\"daphne\"
toINSTALLED_APPS
.INSTALLED_APPS = [\n \"daphne\",\n ...,\n]\n
-
Set your
ASGI_APPLICATION
variable.ASGI_APPLICATION = \"example_project.asgi.application\"\n
ReactPy's has additional configuration available to fit a variety of use cases.
See the ReactPy settings documentation to learn more.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-3-configure-urlspy","title":"Step 3: Configureurls.py
","text":"Add ReactPy HTTP paths to your
urls.pyurlpatterns
in yoururls.py
file.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-4-configure-asgipy","title":"Step 4: Configurefrom django.urls import include, path\n\nurlpatterns = [\n ...,\n path(\"reactpy/\", include(\"reactpy_django.http.urls\")),\n]\n
asgi.py
","text":"Register ReactPy's WebSocket using
asgi.pyREACTPY_WEBSOCKET_ROUTE
in yourasgi.py
file.
Addimport os\n\nfrom django.core.asgi import get_asgi_application\n\n# Ensure DJANGO_SETTINGS_MODULE is set properly based on your project name!\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"example_project.settings\")\n\n# Fetch ASGI application before importing dependencies that require ORM models.\ndjango_asgi_app = get_asgi_application()\n\n\nfrom channels.routing import ProtocolTypeRouter, URLRouter # noqa: E402\nfrom reactpy_django import REACTPY_WEBSOCKET_ROUTE # noqa: E402\n\napplication = ProtocolTypeRouter(\n {\n \"http\": django_asgi_app,\n \"websocket\": URLRouter([REACTPY_WEBSOCKET_ROUTE]),\n }\n)\n
AuthMiddlewareStack
(Optional)There are many situations where you need to access the Django
User
orSession
objects within ReactPy components. For example, if you want to:- Access the
User
that is currently logged in - Access Django's
Session
object - Login or logout the current
User
In these situations will need to ensure you are using
AuthMiddlewareStack
.
Where is myfrom channels.auth import AuthMiddlewareStack # noqa: E402\n\napplication = ProtocolTypeRouter(\n {\n \"http\": django_asgi_app,\n \"websocket\": AuthMiddlewareStack(URLRouter([REACTPY_WEBSOCKET_ROUTE])),\n }\n)\n
asgi.py
?If you do not have an
"},{"location":"learn/add-reactpy-to-a-django-project/#step-5-run-database-migrations","title":"Step 5: Run database migrations","text":"asgi.py
, follow thechannels
installation guide.Run Django's
migrate
command to initialize ReactPy-Django's database table.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-6-check-your-configuration","title":"Step 6: Check your configuration","text":"python manage.py migrate\n
Run Django's
check
command to verify if ReactPy was set up correctly.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-7-create-your-first-component","title":"Step 7: Create your first component","text":"python manage.py check\n
The next step will show you how to create your first ReactPy component.
Prefer a quick summary? Read the At a Glance section below.
At a Glance
my_app/components.py
You will need a file to define your ReactPy components. We recommend creating a
components.py
file within your chosen Django app to start out. Within this file, we will create a simplehello_world
component.from reactpy import component, html\n\n@component\ndef hello_world(recipient: str):\n return html.h1(f\"Hello {recipient}!\")\n
my_app/templates/my_template.html
In your Django app's HTML template, you can now embed your ReactPy component using the
component
template tag. Within this tag, you will need to type in the dotted path to the component.Additionally, you can pass in
args
andkwargs
into your component function. After reading the code below, pay attention to how the function definition forhello_world
(from the previous example) accepts arecipient
argument.
"},{"location":"learn/your-first-component/","title":"Your First Component","text":""},{"location":"learn/your-first-component/#overview","title":"Overview","text":"{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n </body>\n</html>\n
Components are one of the core concepts of ReactPy. They are the foundation upon which you build user interfaces (UI), which makes them the perfect place to start your journey!
Note
If you have reached this point, you should have already installed ReactPy-Django through the previous steps.
"},{"location":"learn/your-first-component/#selecting-a-django-app","title":"Selecting a Django App","text":"You will now need to pick at least one Django app to start using ReactPy-Django on.
For the following examples, we will assume the following:
- You have a Django app named
my_app
, which was created by Django'sstartapp
command. - You have placed
my_app
directly into your Django project folder (./example_project/my_app
). This is common for small projects.
ReactPy-Django has no project structure requirements. Organize everything as you wish, just like any Django project.
"},{"location":"learn/your-first-component/#defining-a-component","title":"Defining a component","text":"You will need a file to start creating ReactPy components.
We recommend creating a
components.py
file within your chosen Django app to start out. For this example, the file path will look like this:./example_project/my_app/components.py
.Within this file, you can define your component functions using ReactPy's
components.py@component
decorator.
What should I name my ReactPy files and functions?from reactpy import component, html\n\n@component\ndef hello_world(recipient: str):\n return html.h1(f\"Hello {recipient}!\")\n
You have full freedom in naming/placement of your files and functions.
We recommend creating a
components.py
for small Django apps. If your app has a lot of components, you should consider breaking them apart into individual modules such ascomponents/navbar.py
.Ultimately, components are referenced by Python dotted path in
What does the decorator actually do?my_template.html
(see next step). This path must be valid to Python'simportlib
.While not all components need to be decorated, there are a few features this decorator adds to your components.
- The ability to be used as a root component.
- The decorator is required for any component that you want to reference in your Django templates (see next step).
- The ability to use hooks.
- The decorator is required on any component where hooks are defined.
- Scoped failures.
- If a decorated component generates an exception, then only that one component will fail to render.
In your Django app's HTML template, you can now embed your ReactPy component using the
{% component %}
template tag. Within this tag, you will need to type in the dotted path to the component.Additionally, you can pass in
my_template.htmlargs
andkwargs
into your component function. After reading the code below, pay attention to how the function definition forhello_world
(from the previous step) accepts arecipient
argument.
Do not use context variables for the component path{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n </body>\n</html>\n
The ReactPy component finder requires that your component path is a string.
Do not use Django template/context variables for the component path. Failure to follow this warning will result in render failures.
For example, do not do the following:
my_template.htmlviews.py<!-- This is good -->\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n\n<!-- This is bad -->\n{% component my_variable recipient=\"World\" %}\n
from django.shortcuts import render\n\n\ndef example_view(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_variable\": \"example_project.my_app.components.hello_world\"},\n )\n
Note: If you decide to not follow this warning, you will need to use the
Can I use multiple components on one page?register_component
function to manually register your components.You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use ReactPy will typically involve many components on one page.
my_template.html{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n <h1>{% component \"example_project.my_app.components.my_title\" %}</h1>\n <p>{% component \"example_project.my_app_2.components.goodbye_world\" class=\"bold small-font\" %}</p>\n{% component \"example_project.my_app_3.components.simple_button\" %}\n </body>\n</html>\n
Please note that components separated like this will not be able to interact with each other, except through database queries.
Additionally, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one component within your
Where is my templates folder?<body>
tag.If you do not have a
"},{"location":"learn/your-first-component/#setting-up-a-django-view","title":"Setting up a Django view","text":"./templates/
folder in your Django app, you can simply create one! Keep in mind, templates within this folder will not be detected by Django unless you add the corresponding Django app tosettings.py:INSTALLED_APPS
.Within your Django app's
views.pyviews.py
file, you will need to create a view function to render the HTML templatemy_template.html
(from the previous step).from django.shortcuts import render\n\n\ndef index(request):\n return render(request, \"my_template.html\")\n
We will add this new view into your
urls.pyurls.py
and define what URL it should be accessible at.
Which urls.py do I add my views to?from django.urls import path\nfrom example import views\n\nurlpatterns = [\n path(\"example/\", views.index),\n]\n
For simple Django projects, you can easily add all of your views directly into the Django project's
urls.py
. However, as you start increase your project's complexity you might end up with way too much within one file.Once you reach that point, we recommend creating an individual
urls.py
within each of your Django apps.Then, within your Django project's
"},{"location":"learn/your-first-component/#viewing-your-component","title":"Viewing your component","text":"urls.py
you will use Django'sinclude
function to link it all together.To test your new Django view, run the following command to start up a development web server.
python manage.py runserver\n
Now you can navigate to your Django project URL that contains a ReactPy component, such as
http://127.0.0.1:8000/example/
(from the previous step).If you copy-pasted our example component, you will now see your component display \"Hello World\".
Do not usemanage.py runserver
for productionThis command is only intended for development purposes. For production deployments make sure to read Django's documentation.
"},{"location":"learn/your-first-component/#learn-more","title":"Learn more","text":"Congratulations! If you followed the previous steps, you have now created a \"Hello World\" component using ReactPy-Django!
Deep Dive
The docs you are reading only covers our Django integration. To learn more, check out one of the following links:
- ReactPy-Django Feature Reference
- ReactPy Core Documentation
- Ask Questions on Discord
Additionally, the vast majority of tutorials/guides you find for ReactJS can be applied to ReactPy.
"},{"location":"reference/components/","title":"Components","text":""},{"location":"reference/components/#overview","title":"Overview","text":"We supply some pre-designed that components can be used to help simplify development.
"},{"location":"reference/components/#pyscript-component","title":"PyScript Component","text":"This allows you to embedded any number of client-side PyScript components within traditional ReactPy components.
By default, the only dependencies available are the Python standard library,
pyscript
,pyodide
,reactpy
core.Your PyScript component file requires a
components.pyroot.pymy_template.htmldef root()
component to function as the entry point.from reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n \"This text is from my server-side component\",\n pyscript_component(\"./example_project/my_app/components/root.py\"),\n )\n
from reactpy import component, html\n\n\n@component\ndef root():\n return html.div(\"This text is from my client-side component\")\n
See Interface{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.server_side_component\" %}\n</body>\n\n</html>\n
Parameters
Name Type Description Default*file_paths
str
File path to your client-side component. If multiple paths are provided, the contents are automatically merged. N/Ainitial
str | VdomDict | ComponentType
The initial HTML that is displayed prior to the PyScript component loads. This can either be a string containing raw HTML, areactpy.html
snippet, or a non-interactive component.\"\"
root
str
The name of the root component function.\"root\"
You must callpyscript_setup
in your Django template before using this tag!This requires using of the
my_template.html{% pyscript_setup %}
template tag to initialize PyScript on the client.
How do I execute JavaScript within PyScript components?{% load reactpy %}\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
PyScript components have the ability to directly execute standard library JavaScript using the
pyodide
js
module orpyscript
foreign function interface.The
root.pyjs
module has access to everything within the browser's JavaScript environment. Therefore, any global JavaScript functions loaded within your HTML<head>
can be called as well. However, be mindful of JavaScript load order!import js\nfrom reactpy import component, html\n\n\n@component\ndef root():\n\n def onClick(event):\n js.document.title = \"New window title\"\n\n return html.button({\"onClick\": onClick}, \"Click Me!\")\n
To import JavaScript modules in a fashion similar to
root.pymy_template.htmlimport {moment} from 'static/moment.js'
, you will need to configure your{% pyscript_setup %}
block to make the module available to PyScript. This module will be accessed withinpyscript.js_modules.*
. For more information, see the PyScript JS modules docs.from reactpy import component, html\n\n\n@component\ndef root():\n from pyscript.js_modules import moment\n\n return html.div(\n {\"id\": \"moment\"},\n \"Using the JavaScript package 'moment' to calculate time: \",\n moment.default().format(\"YYYY-MM-DD HH:mm:ss\"),\n )\n
Does my entire component need to be contained in one file?{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup extra_js='{\"/static/moment.js\":\"moment\"}' %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.root.py\" %}\n</body>\n\n</html>\n
Splitting a large file into multiple files is a common practice in software development.
However, PyScript components are run on the client browser. As such, they do not have access to your local development environment, and thus cannot
import
any local Python files.If your PyScript component file gets too large, you can declare multiple file paths instead. These files will automatically combined by ReactPy.
Here is how we recommend splitting your component into multiple files while avoiding local imports but retaining type hints.
components.pyroot.pychild.pyfrom reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript_component(\n \"./example_project/my_app/components/root.py\",\n \"./example_project/my_app/components/child.py\",\n ),\n )\n
from typing import TYPE_CHECKING\n\nfrom reactpy import component, html\n\nif TYPE_CHECKING:\n from .child import child_component\n\n\n@component\ndef root():\n return html.div(\"This text is from the root component.\", child_component())\n
How do I display something while the component is loading?from reactpy import component, html\n\n\n@component\ndef child_component():\n return html.div(\"This is a child component from a different file.\")\n
You can configure the
initial
keyword to display HTML while your PyScript component is loading.The value for
components.pyinitial
is most commonly be areactpy.html
snippet or a non-interactive@component
.from reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript_component(\n \"./example_project/my_app/components/root.py\",\n initial=html.div(\"Loading ...\"),\n ),\n )\n
However, you can also use a string containing raw HTML.
components.py
Can I use a different name for my root component?from reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript_component(\n \"./example_project/my_app/components/root.py\",\n initial=\"<div> Loading ... </div>\",\n ),\n )\n
Yes, you can use the
components.pymain.pyroot
keyword to specify a different name for your root function.from reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript_component(\n \"./example_project/my_app/components/main.py\",\n root=\"main\",\n ),\n )\n
"},{"location":"reference/components/#view-to-component","title":"View To Component","text":"from reactpy import component, html\n\n\n@component\ndef main():\n return html.div(\"Hello, World!\")\n
Automatically convert a Django view into a component.
At this time, this works best with static views with no interactivity.
Compatible with sync or async Function Based Views and Class Based Views.
components.pyviews.pyfrom reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\nhello_world_component = view_to_component(views.hello_world)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_component(),\n )\n
See Interfacefrom django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
Parameters
Name Type Description Defaultview
Callable | View | str
The view to convert, or the view's dotted path as a string. N/Atransforms
Sequence[Callable[[VdomDict], Any]]
A list of functions that transforms the newly generated VDOM. The functions will be called on each VDOM node.tuple
strict_parsing
bool
IfTrue
, an exception will be generated if the HTML does not perfectly adhere to HTML5.True
Returns
Type Descriptionconstructor
A function that takesrequest, *args, key, **kwargs
and returns a ReactPy component. Note that*args
and**kwargs
are directly provided to your view. Existing limitationsThere are currently several limitations of using
view_to_component
that may be resolved in a future version.- 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
<a href='example/'></a>
) click events.
Class Based Views are accepted by
view_to_component
as an argument.Calling
components.pyviews.pyas_view()
is optional, but recommended.from reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\nhello_world_component = view_to_component(views.HelloWorld.as_view())\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_component(),\n )\n
How do I providefrom django.http import HttpResponse\nfrom django.views import View\n\n\nclass HelloWorld(View):\n def get(self, request):\n return HttpResponse(\"Hello World!\")\n
request
,args
, andkwargs
to a converted view?This component accepts
components.pyviews.pyrequest
,*args
, and**kwargs
arguments, which are sent to your provided view.from django.http import HttpRequest\nfrom reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\nhello_world_component = view_to_component(views.hello_world)\n\n\n@component\ndef my_component():\n request = HttpRequest()\n request.method = \"GET\"\n\n return html.div(\n hello_world_component(\n request, # This request object is optional.\n \"value_1\",\n \"value_2\",\n kwarg1=\"abc\",\n kwarg2=\"123\",\n ),\n )\n
How do I customize this component's behavior?from django.http import HttpResponse\n\n\ndef hello_world(request, arg1, arg2, kwarg1=None, kwarg2=None):\n return HttpResponse(f\"Hello World! {arg1} {arg2} {kwarg1} {kwarg2}\")\n
This component accepts arguments that can be used to customize its behavior.
Below are all the arguments that can be used.
strict_parsing
By default, an exception will be generated if your view's HTML does not perfectly adhere to HTML5.
However, there are some circumstances where you may not have control over the original HTML, so you may be unable to fix it. Or you may be relying on non-standard HTML tags such as
<my-tag> Hello World </my-tag>
.In these scenarios, you may want to rely on best-fit parsing by setting the
components.pyviews.pystrict_parsing
parameter toFalse
. This useslibxml2
recovery algorithm, which is designed to be similar to how web browsers would attempt to parse non-standard or broken HTML.from reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\nhello_world_component = view_to_component(views.hello_world)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_component(),\n )\n
from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
transforms
After your view has been turned into VDOM (python dictionaries),
view_to_component
will call yourtransforms
functions on every VDOM node.This allows you to modify your view prior to rendering.
For example, if you are trying to modify the text of a node with a certain
components.pyviews.pyid
, you can create a transform like such:from reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\n\ndef example_transform(vdom):\n attributes = vdom.get(\"attributes\")\n if attributes and attributes.get(\"id\") == \"hello-world\":\n vdom[\"children\"][0] = \"Farewell World!\"\n\n\nhello_world_component = view_to_component(\n views.hello_world, transforms=[example_transform]\n)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_component(),\n )\n
"},{"location":"reference/components/#view-to-iframe","title":"View To Iframe","text":"from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse('<div id=\"hello-world\"> Hello World! </div>')\n
Automatically convert a Django view into an
iframe
element.The contents of this
iframe
is handled entirely by traditional Django view rendering. While this solution is compatible with more views thanview_to_component
, it comes with different limitations.Compatible with sync or async Function Based Views and Class Based Views.
components.pyviews.pyapps.pyfrom reactpy import component, html\nfrom reactpy_django.components import view_to_iframe\n\nfrom . import views\n\nhello_world_iframe = view_to_iframe(views.hello_world)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_iframe(),\n )\n
from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
See Interfacefrom django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.hello_world)\n
Parameters
Name Type Description Defaultview
Callable | View | str
The view function or class to convert. N/Aextra_props
Mapping[str, Any] | None
Additional properties to add to theiframe
element.None
Returns
Type Descriptionconstructor
A function that takes*args, key, **kwargs
and returns a ReactPy component. Note that*args
and**kwargs
are directly provided to your view. Existing limitationsThere are currently several limitations of using
view_to_iframe
that may be resolved in a future version.- No built-in method of signalling events back to the parent component.
- All provided
*args
and*kwargs
must be serializable values, since they are encoded into the URL. - The
iframe
will always load after the parent component. - CSS styling for
iframe
elements tends to be awkward/difficult.
Class Based Views are accepted by
view_to_iframe
as an argument.Calling
components.pyviews.pyapps.pyas_view()
is optional, but recommended.from reactpy import component, html\nfrom reactpy_django.components import view_to_iframe\n\nfrom . import views\n\nhello_world_iframe = view_to_iframe(views.HelloWorld.as_view())\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_iframe(),\n )\n
from django.http import HttpResponse\nfrom django.views import View\n\n\nclass HelloWorld(View):\n def get(self, request):\n return HttpResponse(\"Hello World!\")\n
How do I providefrom django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.HelloWorld)\n
args
andkwargs
to a converted view?This component accepts
*args
and**kwargs
arguments, which are sent to your provided view.All provided
components.pyviews.pyapps.py*args
and*kwargs
must be serializable values, since they are encoded into the URL.from reactpy import component, html\nfrom reactpy_django.components import view_to_iframe\n\nfrom . import views\n\nhello_world_iframe = view_to_iframe(\n views.hello_world,\n)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_iframe(\n \"value_1\",\n \"value_2\",\n kwarg1=\"abc\",\n kwarg2=\"123\",\n ),\n )\n
from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
How do I customize this component's behavior?from django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.hello_world)\n
This component accepts arguments that can be used to customize its behavior.
Below are all the arguments that can be used.
extra_props
This component accepts a
extra_props
parameter, which is a dictionary of additional properties to add to theiframe
element.For example, if you want to add a
components.pyviews.pyapps.pytitle
attribute to theiframe
element, you can do so like such:from reactpy import component, html\nfrom reactpy_django.components import view_to_iframe\n\nfrom . import views\n\nhello_world_iframe = view_to_iframe(\n views.hello_world, extra_props={\"title\": \"Hello World!\"}\n)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_iframe(),\n )\n
from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
"},{"location":"reference/components/#django-css","title":"Django CSS","text":"from django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.hello_world)\n
Allows you to defer loading a CSS stylesheet until a component begins rendering. This stylesheet must be stored within Django's static files.
components.py
See Interfacefrom reactpy import component, html\nfrom reactpy_django.components import django_css\n\n\n@component\ndef my_component():\n return html.div(\n django_css(\"css/buttons.css\"),\n html.button(\"My Button!\"),\n )\n
Parameters
Name Type Description Defaultstatic_path
str
The path to the static file. This path is identical to what you would use on Django's{% static %}
template tag. N/Akey
Key | None
A key to uniquely identify this component which is unique amongst a component's immediate siblingsNone
Returns
Type DescriptionComponent
A ReactPy component. Can I load static CSS usinghtml.link
instead?While you can load stylesheets with
html.link
, keep in mind that loading this way does not ensure load order. Thus, your stylesheet will be loaded after your component is displayed. This would likely cause unintended visual behavior, so use this at your own discretion.Here's an example on what you should avoid doing for Django static files:
How do I load external CSS?from django.templatetags.static import static\nfrom reactpy import component, html\n\n\n@component\ndef my_component():\n return html.div(\n html.link({\"rel\": \"stylesheet\", \"href\": static(\"css/buttons.css\")}),\n html.button(\"My Button!\"),\n )\n
django_css
can only be used with local static files.For external CSS, you should use
html.link
.
Why not load my CSS infrom reactpy import component, html\n\n\n@component\ndef my_component():\n return html.div(\n html.link(\n {\"rel\": \"stylesheet\", \"href\": \"https://example.com/external-styles.css\"}\n ),\n html.button(\"My Button!\"),\n )\n
<head>
?Traditionally, stylesheets are loaded in your
<head>
using Django's{% static %}
template tag.However, to help improve webpage load times you can use this
"},{"location":"reference/components/#django-js","title":"Django JS","text":"django_css
component to defer loading your stylesheet until it is needed.Allows you to defer loading JavaScript until a component begins rendering. This JavaScript must be stored within Django's static files.
components.py
See Interfacefrom reactpy import component, html\nfrom reactpy_django.components import django_js\n\n\n@component\ndef my_component():\n return html.div(\n html.button(\"My Button!\"),\n django_js(\"js/scripts.js\"),\n )\n
Parameters
Name Type Description Defaultstatic_path
str
The path to the static file. This path is identical to what you would use on Django's{% static %}
template tag. N/Akey
Key | None
A key to uniquely identify this component which is unique amongst a component's immediate siblingsNone
Returns
Type DescriptionComponent
A ReactPy component. Can I load static JavaScript usinghtml.script
instead?While you can load JavaScript with
html.script
, keep in mind that loading this way does not ensure load order. Thus, your JavaScript will likely be loaded at an arbitrary time after your component is displayed.Here's an example on what you should avoid doing for Django static files:
How do I load external JS?from django.templatetags.static import static\nfrom reactpy import component, html\n\n\n@component\ndef my_component():\n return html.div(\n html.script({\"src\": static(\"js/scripts.js\")}),\n html.button(\"My Button!\"),\n )\n
django_js
can only be used with local static files.For external JavaScript, you should use
html.script
.
Why not load my JS infrom reactpy import component, html\n\n\n@component\ndef my_component():\n return html.div(\n html.script({\"src\": \"https://example.com/external-scripts.js\"}),\n html.button(\"My Button!\"),\n )\n
<head>
?Traditionally, JavaScript is loaded in your
<head>
using Django's{% static %}
template tag.However, to help improve webpage load times you can use this
"},{"location":"reference/decorators/","title":"Decorators","text":""},{"location":"reference/decorators/#overview","title":"Overview","text":"django_js
component to defer loading your JavaScript until it is needed.Decorator functions can be used within your
"},{"location":"reference/decorators/#user-passes-test","title":"User Passes Test","text":"components.py
to help simplify development.You can limit component access to users that pass a test function by using this decorator.
This decorator is inspired by Django's
components.pyuser_passes_test
decorator, but works with ReactPy components.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.decorators import user_passes_test\n\n\ndef is_authenticated(user):\n return user.is_authenticated\n\n\n@user_passes_test(is_authenticated)\n@component\ndef my_component():\n return html.div(\"I am logged in!\")\n
Parameters
Name Type Description Defaulttest_func
Callable[[AbstractUser], bool]
A function that accepts aUser
returns a boolean. N/Afallback
Any | None
The content to be rendered if the test fails. Typically is a ReactPy component or VDOM (reactpy.html
snippet).Returns
Type DescriptionComponentConstructor
A ReactPy component constructor. How do I render a different component if the test fails?You can use a component with the
components.pyfallback
argument, as seen below.
How do I render a simplefrom reactpy import component, html\nfrom reactpy_django.decorators import user_passes_test\n\n\n@component\ndef my_component_fallback():\n return html.div(\"I am NOT logged in!\")\n\n\ndef is_authenticated(user):\n return user.is_authenticated\n\n\n@user_passes_test(is_authenticated, fallback=my_component_fallback)\n@component\ndef my_component():\n return html.div(\"I am logged in!\")\n
reactpy.html
snippet if the test fails?You can use a
components.pyreactpy.html
snippet with thefallback
argument, as seen below.
"},{"location":"reference/hooks/","title":"Hooks","text":""},{"location":"reference/hooks/#overview","title":"Overview","text":"from reactpy import component, html\nfrom reactpy_django.decorators import user_passes_test\n\n\ndef is_authenticated(user):\n return user.is_authenticated\n\n\n@user_passes_test(is_authenticated, fallback=html.div(\"I am NOT logged in!\"))\n@component\ndef my_component():\n return html.div(\"I am logged in!\")\n
Prefabricated hooks can be used within your
components.py
to help simplify development.Note
Looking for standard React hooks?
This package only contains Django specific hooks. Standard hooks can be found within
"},{"location":"reference/hooks/#database-hooks","title":"Database Hooks","text":""},{"location":"reference/hooks/#use-query","title":"Use Query","text":"reactive-python/reactpy
.Execute functions in the background and return the result, typically to read data from the Django ORM.
The default postprocessor expects your query function to
return
a DjangoModel
orQuerySet
. This needs to be changed or disabled to execute other types of queries.Query functions can be sync or async.
components.pymodels.pyfrom channels.db import database_sync_to_async\nfrom example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_query\n\n\nasync def get_items():\n return await database_sync_to_async(TodoItem.objects.all)()\n\n\n@component\ndef todo_list():\n item_query = use_query(get_items)\n\n if item_query.loading:\n rendered_items = html.h2(\"Loading...\")\n elif item_query.error or not item_query.data:\n rendered_items = html.h2(\"Error when loading!\")\n else:\n rendered_items = html.ul(\n [html.li(item.text, key=item.pk) for item in item_query.data]\n )\n\n return html.div(\"Rendered items: \", rendered_items)\n
See Interfacefrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
Parameters
Name Type Description Defaultquery
Callable[FuncParams, Awaitable[Inferred]] | Callable[FuncParams, Inferred]
A function that executes a query and returns some data. N/Akwargs
dict[str, Any] | None
Keyword arguments to passed into thequery
function.None
thread_sensitive
bool
Whether to run your query function in thread sensitive mode. This mode only applies to sync query functions, and is turned on by default due to Django ORM limitations.True
postprocessor
AsyncPostprocessor | SyncPostprocessor | None
A callable that processes the querydata
before it is returned. The first argument of postprocessor function must be the querydata
. All proceeding arguments are optionalpostprocessor_kwargs
. This postprocessor function must return the modifieddata
.None
postprocessor_kwargs
dict[str, Any] | None
Keyworded arguments passed into thepostprocessor
function.None
Returns
Type DescriptionQuery[Inferred]
An object containingloading
/error
states, yourdata
(if the query has successfully executed), and arefetch
callable that can be used to re-run the query. How can I provide arguments to my query function?
components.pykwargs
can be provided to your query function via thekwargs=...
parameter.
How can I customize this hook's behavior?from reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef example_query(value: int, other_value: bool = False): ...\n\n\n@component\ndef my_component():\n query = use_query(example_query, {\"value\": 123, \"other_value\": True})\n\n return str(query.data)\n
This hook has several parameters that can be used to customize behavior.
Below are examples of values that can be modified.
thread_sensitive
Whether to run your synchronous query function in thread sensitive mode. Thread sensitive mode is turned on by default due to Django ORM limitations. See Django's
sync_to_async
docs docs for more information.This setting only applies to sync query functions, and will be ignored for async functions.
components.pyfrom reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef execute_thread_safe_operation():\n\"\"\"This is an example query function that does some thread-safe operation.\"\"\"\n pass\n\n\n@component\ndef my_component():\n query = use_query(execute_thread_safe_operation, thread_sensitive=False)\n\n if query.loading or query.error:\n return None\n\n return str(query.data)\n
postprocessor
By default, automatic recursive fetching of
ManyToMany
orForeignKey
fields is enabled within thedjango_query_postprocessor
. This is needed to preventSynchronousOnlyOperation
exceptions when accessing these fields within your ReactPy components.However, if you...
- Want to use this hook to defer IO intensive tasks to be computed in the background
- Want to to utilize
use_query
with a different ORM
... then you can either set a custom
components.pypostprocessor
, or disable all postprocessing behavior by modifying thepostprocessor=...
parameter. In the example below, we will set thepostprocessor
toNone
to disable postprocessing behavior.from reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef execute_io_intensive_operation():\n\"\"\"This is an example query function that does something IO intensive.\"\"\"\n pass\n\n\n@component\ndef my_component():\n query = use_query(\n execute_io_intensive_operation,\n postprocessor=None,\n )\n\n if query.loading or query.error:\n return None\n\n return str(query.data)\n
If you wish to create a custom
components.pypostprocessor
, you will need to create a function where the first must be the querydata
. All proceeding arguments are optionalpostprocessor_kwargs
(see below). Thispostprocessor
function must return the modifieddata
.from reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef my_postprocessor(data, example_kwarg=True):\n if example_kwarg:\n return data\n\n return dict(data)\n\n\ndef execute_io_intensive_operation():\n\"\"\"This is an example query function that does something IO intensive.\"\"\"\n pass\n\n\n@component\ndef my_component():\n query = use_query(\n execute_io_intensive_operation,\n postprocessor=my_postprocessor,\n postprocessor_kwargs={\"example_kwarg\": False},\n )\n\n if query.loading or query.error:\n return None\n\n return str(query.data)\n
postprocessor_kwargs
By default, automatic recursive fetching of
ManyToMany
orForeignKey
fields is enabled within thedjango_query_postprocessor
. This is needed to preventSynchronousOnlyOperation
exceptions when accessing these fields within your ReactPy components.However, if you have deep nested trees of relational data, this may not be a desirable behavior. In these scenarios, you may prefer to manually fetch these relational fields using a second
use_query
hook.You can disable the prefetching behavior of the default
components.pypostprocessor
(located atreactpy_django.utils.django_query_postprocessor
) via thepostprocessor_kwargs=...
parameter.from example.models import TodoItem\nfrom reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef get_model_with_relationships():\n\"\"\"This is an example query function that gets `MyModel` which has a ManyToMany field, and\n additionally other models that have formed a ForeignKey association to `MyModel`.\n\n ManyToMany Field: `many_to_many_field`\n ForeignKey Field: `foreign_key_field_set`\n \"\"\"\n return TodoItem.objects.get(id=1)\n\n\n@component\ndef my_component():\n query = use_query(\n get_model_with_relationships,\n postprocessor_kwargs={\"many_to_many\": False, \"many_to_one\": False},\n )\n\n if query.loading or query.error or not query.data:\n return None\n\n # By disabling `many_to_many` and `many_to_one`, accessing these fields will now\n # generate a `SynchronousOnlyOperation` exception\n return f\"{query.data.many_to_many_field} {query.data.foriegn_key_field_set}\"\n
Note: In Django's ORM design, the field name to access foreign keys is postfixed with
Can I make ORM calls without hooks?_set
by default.Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a
SynchronousOnlyOperation
exception.These
Can I make a failed query try again?SynchronousOnlyOperation
exceptions may be removed in a future version of Django. However, it is best practice to always perform IO operations (such as ORM queries) via hooks to prevent performance issues.Yes,
use_mutation
can be re-executed by callingreset()
on youruse_mutation
instance.For example, take a look at
components.pymodels.pyreset_event
below.from example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_mutation\n\n\ndef add_item(text: str):\n TodoItem(text=text).save()\n\n\n@component\ndef todo_list():\n item_mutation = use_mutation(add_item)\n\n def reset_event(event):\n item_mutation.reset()\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n if item_mutation.loading:\n mutation_status = html.h2(\"Adding...\")\n elif item_mutation.error:\n mutation_status = html.button({\"on_click\": reset_event}, \"Error: Try again!\")\n else:\n mutation_status = html.h2(\"Mutation done.\")\n\n return html.div(\n html.label(\"Add an item:\"),\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n )\n
Why does the example query function returnfrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
TodoItem.objects.all()
?This design decision was based on Apollo's
useQuery
hook, but ultimately helps avoid Django'sSynchronousOnlyOperation
exceptions.With the
"},{"location":"reference/hooks/#use-mutation","title":"Use Mutation","text":"Model
orQuerySet
your function returns, this hook uses the default postprocessor to ensure that all deferred or lazy fields are executed.Modify data in the background, typically to create/update/delete data from the Django ORM.
Mutation functions can
return False
to manually prevent yourrefetch=...
function from executing. All other returns are ignored.Mutation functions can be sync or async.
components.pymodels.pyfrom example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_mutation\n\n\nasync def add_item(text: str):\n await TodoItem(text=text).asave()\n\n\n@component\ndef todo_list():\n item_mutation = use_mutation(add_item)\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n if item_mutation.loading:\n mutation_status = html.h2(\"Adding...\")\n elif item_mutation.error:\n mutation_status = html.h2(\"Error when adding!\")\n else:\n mutation_status = html.h2(\"Mutation done.\")\n\n return html.div(\n html.label(\"Add an item:\"),\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n )\n
See Interfacefrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
Parameters
Name Type Description Defaultmutation
Callable[FuncParams, bool | None] | Callable[FuncParams, Awaitable[bool | None]]
A callable that performs Django ORM create, update, or delete functionality. If this function returnsFalse
, then yourrefetch
function will not be used. N/Athread_sensitive
bool
Whether to run the mutation in thread sensitive mode. This mode only applies to sync mutation functions, and is turned on by default due to Django ORM limitations.True
refetch
Callable[..., Any] | Sequence[Callable[..., Any]] | None
A query function (the function you provide to youruse_query
hook) or a sequence of query functions that need arefetch
if the mutation succeeds. This is useful for refreshing data after a mutation has been performed.None
Returns
Type DescriptionMutation[FuncParams]
An object containingloading
/error
states, and areset
callable that will setloading
/error
states to defaults. This object can be called to run the query. How can I provide arguments to my mutation function?
components.py*args
and**kwargs
can be provided to your mutation function viamutation(...)
parameters.
How can I customize this hook's behavior?from reactpy import component\nfrom reactpy_django.hooks import use_mutation\n\n\ndef example_mutation(value: int, other_value: bool = False):\n ...\n\n\n@component\ndef my_component():\n mutation = use_mutation(example_mutation)\n\n mutation(123, other_value=True)\n\n ...\n
This hook has several parameters that can be used to customize behavior.
Below are examples of values that can be modified.
thread_sensitive
Whether to run your synchronous mutation function in thread sensitive mode. Thread sensitive mode is turned on by default due to Django ORM limitations. See Django's
sync_to_async
docs docs for more information.This setting only applies to sync query functions, and will be ignored for async functions.
components.py
Can I make ORM calls without hooks?from reactpy import component, html\nfrom reactpy_django.hooks import use_mutation\n\n\ndef execute_thread_safe_mutation(text):\n\"\"\"This is an example mutation function that does some thread-safe operation.\"\"\"\n pass\n\n\n@component\ndef my_component():\n item_mutation = use_mutation(\n execute_thread_safe_mutation,\n thread_sensitive=False,\n )\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n if item_mutation.loading or item_mutation.error:\n mutation_status = html.h2(\"Doing something...\")\n elif item_mutation.error:\n mutation_status = html.h2(\"Error!\")\n else:\n mutation_status = html.h2(\"Done.\")\n\n return html.div(\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n )\n
Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a
SynchronousOnlyOperation
exception.These
Can I make a failed mutation try again?SynchronousOnlyOperation
exceptions may be removed in a future version of Django. However, it is best practice to always perform IO operations (such as ORM queries) via hooks to prevent performance issues.Yes,
use_mutation
can be re-executed by callingreset()
on youruse_mutation
instance.For example, take a look at
components.pymodels.pyreset_event
below.from example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_mutation\n\n\ndef add_item(text: str):\n TodoItem(text=text).save()\n\n\n@component\ndef todo_list():\n item_mutation = use_mutation(add_item)\n\n def reset_event(event):\n item_mutation.reset()\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n if item_mutation.loading:\n mutation_status = html.h2(\"Adding...\")\n elif item_mutation.error:\n mutation_status = html.button({\"on_click\": reset_event}, \"Error: Try again!\")\n else:\n mutation_status = html.h2(\"Mutation done.\")\n\n return html.div(\n html.label(\"Add an item:\"),\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n )\n
Canfrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
use_mutation
trigger a refetch ofuse_query
?Yes,
use_mutation
can queue a refetch of ause_query
via therefetch=...
argument.The example below is a merge of the
use_query
anduse_mutation
examples above with the addition of ause_mutation(refetch=...)
argument.Please note that
components.pymodels.pyrefetch
will cause alluse_query
hooks that useget_items
in the current component tree will be refetched.from example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_mutation, use_query\n\n\ndef get_items():\n return TodoItem.objects.all()\n\n\ndef add_item(text: str):\n TodoItem(text=text).save()\n\n\n@component\ndef todo_list():\n item_query = use_query(get_items)\n item_mutation = use_mutation(add_item, refetch=get_items)\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n # Handle all possible query states\n if item_query.loading:\n rendered_items = html.h2(\"Loading...\")\n elif item_query.error or not item_query.data:\n rendered_items = html.h2(\"Error when loading!\")\n else:\n rendered_items = html.ul(\n html.li(item.text, key=item.pk) for item in item_query.data\n )\n\n # Handle all possible mutation states\n if item_mutation.loading:\n mutation_status = html.h2(\"Adding...\")\n elif item_mutation.error:\n mutation_status = html.h2(\"Error when adding!\")\n else:\n mutation_status = html.h2(\"Mutation done.\")\n\n return html.div(\n html.label(\"Add an item:\"),\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n rendered_items,\n )\n
"},{"location":"reference/hooks/#use-user-data","title":"Use User Data","text":"from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
Store or retrieve a
dict
containing user data specific to the connection'sUser
.This hook is useful for storing user-specific data, such as preferences, settings, or any generic key-value pairs.
User data saved with this hook is stored within the
components.pyREACTPY_DATABASE
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_user_data\n\n\n@component\ndef my_component():\n query, mutation = use_user_data()\n\n def on_submit(event):\n if event[\"key\"] == \"Enter\" and query.data:\n new_key = str(len(query.data))\n mutation({**query.data, new_key: event[\"target\"][\"value\"]})\n\n return html.div(\n html.div(f\"Data: {query.data}\"),\n html.div(f\"Loading: {query.loading | mutation.loading}\"),\n html.div(f\"Error(s): {query.error} {mutation.error}\"),\n html.input({\"on_key_press\": on_submit}),\n )\n
Parameters
Name Type Description Defaultdefault_data
None | dict[str, Callable[[], Any] | Callable[[], Awaitable[Any]] | Any]
A dictionary containing{key: default_value}
pairs. For computationally intensive defaults, yourdefault_value
can be sync or async functions that return the value to set.None
save_default_data
bool
IfTrue
,default_data
values will automatically be stored within the database if they do not exist.False
Returns
Type DescriptionUserData
ANamedTuple
containing aQuery
andMutation
objects used to access/modify user data. Read theuse_query
anduse_mutation
docs for more details. How do I set default values?You can configure default user data via the
default_data
parameter.This parameter accepts a dictionary containing a
components.py{key: default_value}
pairs. For computationally intensive defaults, yourdefault_value
can be sync or async functions that return the value to set.
"},{"location":"reference/hooks/#communication-hooks","title":"Communication Hooks","text":""},{"location":"reference/hooks/#use-channel-layer","title":"Use Channel Layer","text":"from reactpy import component, html\nfrom reactpy_django.hooks import use_user_data\n\n\n@component\ndef my_component():\n user_data = use_user_data(\n default_data={\n \"basic_example\": \"123\",\n \"computed_example_sync\": sync_default,\n \"computed_example_async\": async_default,\n }\n )\n\n return html.div(\n html.div(f\"Data: {user_data.query.data}\"),\n )\n\n\ndef sync_default():\n return ...\n\n\nasync def async_default():\n return ...\n
Subscribe to a Django Channels layer to send/receive messages.
Layers are a multiprocessing-safe communication system that allows you to send/receive messages between different parts of your application.
This is often used to create chat systems, synchronize data between components, or signal re-renders from outside your components.
components.py
See Interfacefrom reactpy import component, hooks, html\nfrom reactpy_django.hooks import use_channel_layer\n\n\n@component\ndef my_component():\n async def receive_message(message):\n set_message(message[\"text\"])\n\n async def send_message(event):\n if event[\"key\"] == \"Enter\":\n await sender({\"text\": event[\"target\"][\"value\"]})\n\n message, set_message = hooks.use_state(\"\")\n sender = use_channel_layer(\"my-channel-name\", receiver=receive_message)\n\n return html.div(\n f\"Received: {message}\",\n html.br(),\n \"Send: \",\n html.input({\"type\": \"text\", \"onKeyDown\": send_message}),\n )\n
Parameters
Name Type Description Defaultname
str | None
The name of the channel to subscribe to. If you define agroup_name
, you can keepname
undefined to auto-generate a unique name.None
group_name
str | None
If configured, any messages sent within this hook will be broadcasted to all channels in this group.None
group_add
bool
IfTrue
, the channel will automatically be added to the group when the component mounts.True
group_discard
bool
IfTrue
, the channel will automatically be removed from the group when the component dismounts.True
receiver
AsyncMessageReceiver | None
An async function that receives amessage: dict
from a channel. If more than one receiver waits on the same channel name, a random receiver will get the result.None
layer
str
The channel layer to use. This layer must be defined insettings.py:CHANNEL_LAYERS
.'default'
Returns
Type DescriptionAsyncMessageSender
An async callable that can send amessage: dict
. Extra Django configuration requiredIn order to use this hook, you will need to configure Django to enable channel layers.
The Django Channels documentation has information on what steps you need to take.
In summary, you will need to:
-
Install
redis
on your machine. -
Run the following command to install
channels-redis
in your Python environment.pip install channels-redis\n
-
Configure your
settings.py
to useRedisChannelLayer
as your layer backend.CHANNEL_LAYERS = {\n \"default\": {\n \"BACKEND\": \"channels_redis.core.RedisChannelLayer\",\n \"CONFIG\": {\n \"hosts\": [(\"127.0.0.1\", 6379)],\n },\n },\n}\n
If more than one receiver waits on the same channel, a random one will get the result.
To get around this, you can define a
group_name
to broadcast messages to all channels within a specific group. If you do not define a channelname
while using groups, ReactPy will automatically generate a unique channel name for you.In the example below, all messages sent by the
components.pysender
component will be received by allreceiver
components that exist (across every active client browser).
How do I signal a re-render from something that isn't a component?from reactpy import component, hooks, html\nfrom reactpy_django.hooks import use_channel_layer\n\n\n@component\ndef my_sender_component():\n sender = use_channel_layer(group_name=\"my-group-name\")\n\n async def submit_event(event):\n if event[\"key\"] == \"Enter\":\n await sender({\"text\": event[\"target\"][\"value\"]})\n\n return html.div(\n \"Message Sender: \",\n html.input({\"type\": \"text\", \"onKeyDown\": submit_event}),\n )\n\n\n@component\ndef my_receiver_component_1():\n message, set_message = hooks.use_state(\"\")\n\n async def receive_event(message):\n set_message(message[\"text\"])\n\n use_channel_layer(group_name=\"my-group-name\", receiver=receive_event)\n\n return html.div(f\"Message Receiver 1: {message}\")\n\n\n@component\ndef my_receiver_component_2():\n message, set_message = hooks.use_state(\"\")\n\n async def receive_event(message):\n set_message(message[\"text\"])\n\n use_channel_layer(group_name=\"my-group-name\", receiver=receive_event)\n\n return html.div(f\"Message Receiver 2: {message}\")\n
There are occasions where you may want to signal a re-render from something that isn't a component, such as a Django model signal.
In these cases, you can use the
use_channel_layer
hook to receive a signal within your component, and then use theget_channel_layer().send(...)
to send the signal.In the example below, the sender will send a signal every time
signals.pycomponents.pyExampleModel
is saved. Then, when the receiver component gets this signal, it explicitly callsset_message(...)
to trigger a re-render.from asgiref.sync import async_to_sync\nfrom channels.layers import get_channel_layer\nfrom django.db.models import Model\nfrom django.db.models.signals import pre_save\nfrom django.dispatch import receiver\n\n\nclass ExampleModel(Model): ...\n\n\n@receiver(pre_save, sender=ExampleModel)\ndef my_sender_signal(sender, instance, **kwargs):\n layer = get_channel_layer()\n\n # Example of sending a message to a channel\n async_to_sync(layer.send)(\"my-channel-name\", {\"text\": \"Hello World!\"})\n\n # Example of sending a message to a group channel\n async_to_sync(layer.group_send)(\"my-group-name\", {\"text\": \"Hello World!\"})\n
"},{"location":"reference/hooks/#connection-hooks","title":"Connection Hooks","text":""},{"location":"reference/hooks/#use-connection","title":"Use Connection","text":"from reactpy import component, hooks, html\nfrom reactpy_django.hooks import use_channel_layer\n\n\n@component\ndef my_receiver_component():\n message, set_message = hooks.use_state(\"\")\n\n async def receive_event(message):\n set_message(message[\"text\"])\n\n use_channel_layer(\"my-channel-name\", receiver=receive_event)\n\n return html.div(f\"Message Receiver: {message}\")\n
Returns the active connection, which is either a Django WebSocket or a HTTP Request.
components.py
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_connection\n\n\n@component\ndef my_component():\n connection = use_connection()\n\n return html.div(str(connection))\n
Parameters
None
Returns
Type DescriptionConnection
An object that contains acarrier
(WebSocket
orHttpRequest
),scope
, andlocation
."},{"location":"reference/hooks/#use-scope","title":"Use Scope","text":"Shortcut that returns the WebSocket or HTTP connection's scope.
components.py
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_scope\n\n\n@component\ndef my_component():\n scope = use_scope()\n\n return html.div(str(scope))\n
Parameters
None
Returns
Type DescriptionMutableMapping[str, Any]
The connection'sscope
."},{"location":"reference/hooks/#use-location","title":"Use Location","text":"Shortcut that returns the browser's current
components.pyLocation
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_location\n\n\n@component\ndef my_component():\n location = use_location()\n\n return html.div(location.pathname + location.search)\n
Parameters
None
Returns
Type DescriptionLocation
An object containing the current URL'spathname
andsearch
query."},{"location":"reference/hooks/#use-origin","title":"Use Origin","text":"Shortcut that returns the WebSocket or HTTP connection's
origin
.You can expect this hook to provide strings such as
components.pyhttp://example.com
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_origin\n\n\n@component\ndef my_component():\n origin = use_origin()\n\n return html.div(origin or \"No origin\")\n
Parameters
None
Returns
Type Descriptionstr | None
A string containing the browser's current origin, obtained from WebSocket or HTTP headers (if available)."},{"location":"reference/hooks/#use-root-id","title":"Use Root ID","text":"Shortcut that returns the root component's
id
from the WebSocket or HTTP connection.The root ID is currently a randomly generated
uuid4
(unique across all root component).This is useful when used in combination with
components.pyuse_channel_layer
to send messages to a specific component instance, and/or retain a backlog of messages in case that component is disconnected viause_channel_layer( ... , group_discard=False)
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_root_id\n\n\n@component\ndef my_component():\n root_id = use_root_id()\n\n return html.div(f\"Root ID: {root_id}\")\n
Parameters
None
Returns
Type Descriptionstr
A string containing the root component'sid
."},{"location":"reference/hooks/#use-user","title":"Use User","text":"Shortcut that returns the WebSocket or HTTP connection's
components.pyUser
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_user\n\n\n@component\ndef my_component():\n user = use_user()\n\n return html.div(user.username)\n
Parameters
None
Returns
Type DescriptionAbstractUser
A DjangoUser
, which can also be anAnonymousUser
."},{"location":"reference/html/","title":"HTML","text":""},{"location":"reference/html/#overview","title":"Overview","text":"We supply some pre-generated that HTML nodes can be used to help simplify development.
"},{"location":"reference/html/#pyscript","title":"PyScript","text":"Primitive HTML tag that is leveraged by
reactpy_django.components.pyscript_component
.This can be used as an alternative to the
reactpy.html.script
tag to execute JavaScript and run client-side Python code.Additionally, this tag functions identically to any other tag contained within
components.pymy_template.htmlreactpy.html
, and can be used in the same way.from reactpy import component, html\nfrom reactpy_django.html import pyscript\n\nexample_source_code = \"\"\"\nimport js\n\njs.console.log(\"Hello, World!\")\n\"\"\"\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript(example_source_code.strip()),\n )\n
You must call{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.server_side_component.py\" %}\n</body>\n\n</html>\n
pyscript_setup
in your Django template before using this tag!This requires using of the
my_template.html{% pyscript_setup %}
template tag to initialize PyScript on the client.
"},{"location":"reference/management-commands/","title":"Management Commands","text":""},{"location":"reference/management-commands/#overview","title":"Overview","text":"{% load reactpy %}\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
ReactPy exposes Django management commands that can be used to perform various ReactPy-related tasks.
"},{"location":"reference/management-commands/#clean-reactpy-command","title":"Clean ReactPy Command","text":"Command used to manually clean ReactPy data.
When using this command without arguments, it will perform all cleaning operations. You can limit cleaning to specific operations through arguments such as
--sessions
.Terminal
See Interfacepython manage.py clean_reactpy\n
Type
"},{"location":"reference/router/","title":"URL Router","text":""},{"location":"reference/router/#overview","title":"Overview","text":"python manage.py clean_reactpy --help
to see the available options.A Single Page Application URL router, which is a variant of
reactpy-router
that uses Django conventions.Note
Looking for more details on URL routing?
This package only contains Django specific URL routing features. Standard features can be found within
"},{"location":"reference/router/#django-router","title":"Django Router","text":"reactive-python/reactpy-router
.URL router that enables the ability to conditionally render other components based on the client's current URL
path
.Pitfall
All pages where
django_router
is used must have identical, or more permissive URL exposure within Django's URL patterns. You can think of the router component as a secondary, client-side router. Django still handles the primary server-side routes.We recommend creating a route with a wildcard
components.py.*
to forward routes to ReactPy. For example...re_path(r\"^/router/.*$\", my_reactpy_view)
See Interfacefrom reactpy import component, html\nfrom reactpy_django.router import django_router\nfrom reactpy_router import route\n\n\n@component\ndef my_component():\n return django_router(\n route(\"/router/\", html.div(\"Example 1\")),\n route(\"/router/any/<value>/\", html.div(\"Example 2\")),\n route(\"/router/integer/<int:value>/\", html.div(\"Example 3\")),\n route(\"/router/path/<path:value>/\", html.div(\"Example 4\")),\n route(\"/router/slug/<slug:value>/\", html.div(\"Example 5\")),\n route(\"/router/string/<str:value>/\", html.div(\"Example 6\")),\n route(\"/router/uuid/<uuid:value>/\", html.div(\"Example 7\")),\n route(\"/router/two_values/<int:value>/<str:value2>/\", html.div(\"Example 8\")),\n route(\"/router/*\", html.div(\"Fallback\")),\n )\n
Parameters
Name Type Description Default*routes
Route
An object fromreactpy-router
containing apath
,element
, and child*routes
. N/AReturns
Type DescriptionVdomDict | None
The matched component/path after it has been fully rendered. How is this different fromreactpy_router.simple.router
?This component utilizes
"},{"location":"reference/settings/","title":"Settings","text":""},{"location":"reference/settings/#overview","title":"Overview","text":"reactpy-router
under the hood, but provides a more Django-like URL routing syntax.These are ReactPy-Django's default settings values. You can modify these values in your Django project's
settings.py
to change the behavior of ReactPy.Note
The default configuration of ReactPy is suitable for the vast majority of use cases.
You should only consider changing settings when the necessity arises.
"},{"location":"reference/settings/#general-settings","title":"General Settings","text":""},{"location":"reference/settings/#reactpy_url_prefix","title":"REACTPY_URL_PREFIX
","text":"Default:
\"reactpy/\"
Example Value(s):
\"rp/\"
,\"render/reactpy/\"
The prefix used for all ReactPy WebSocket and HTTP URLs.
"},{"location":"reference/settings/#reactpy_default_query_postprocessor","title":"REACTPY_DEFAULT_QUERY_POSTPROCESSOR
","text":"Default:
\"reactpy_django.utils.django_query_postprocessor\"
Example Value(s):
\"example_project.postprocessor\"
,None
Dotted path to the default
reactpy_django.hooks.use_query
postprocessor function.Postprocessor functions can be async or sync. Here is an example of a sync postprocessor function:
def postprocessor(data):\n del data[\"foo\"]\n return data\n
Set
"},{"location":"reference/settings/#reactpy_auth_backend","title":"REACTPY_DEFAULT_QUERY_POSTPROCESSOR
toNone
to disable the default postprocessor.REACTPY_AUTH_BACKEND
","text":"Default:
\"django.contrib.auth.backends.ModelBackend\"
Example Value(s):
\"example_project.auth.MyModelBackend\"
Dotted path to the Django authentication backend to use for ReactPy components. This is only needed if:
- You are using
settings.py:REACTPY_AUTO_RELOGIN=True
and... - You are using
AuthMiddlewareStack
and... - You are using Django's
AUTHENTICATION_BACKENDS
setting and... - Your Django user model does not define a
backend
attribute.
REACTPY_AUTO_RELOGIN
","text":"Default:
False
Example Value(s):
True
Enabling this will cause component WebSocket connections to automatically re-login users that are already authenticated.
This is useful to continuously update
"},{"location":"reference/settings/#performance-settings","title":"Performance Settings","text":""},{"location":"reference/settings/#reactpy_database","title":"last_login
timestamps and refresh the Django login session.REACTPY_DATABASE
","text":"Default:
\"default\"
Example Value(s):
\"my-reactpy-database\"
Multiprocessing-safe database used by ReactPy for database-backed hooks and features.
If configuring this value, it is mandatory to enable our database router like such:
settings.py
"},{"location":"reference/settings/#reactpy_cache","title":"DATABASE_ROUTERS = [\"reactpy_django.database.Router\", ...]\n
REACTPY_CACHE
","text":"Default:
\"default\"
Example Value(s):
\"my-reactpy-cache\"
Cache used by ReactPy, typically for caching disk operations.
We recommend using
"},{"location":"reference/settings/#reactpy_backhaul_thread","title":"redis
,memcache
, orlocal-memory caching
.REACTPY_BACKHAUL_THREAD
","text":"Default:
False
Example Value(s):
True
Configures whether ReactPy components are rendered in a dedicated thread.
This allows the web server to process other traffic during ReactPy rendering. Vastly improves throughput with web servers such as
hypercorn
anduvicorn
.This setting is incompatible with
"},{"location":"reference/settings/#reactpy_default_hosts","title":"daphne
.REACTPY_DEFAULT_HOSTS
","text":"Default:
None
Example Value(s):
[\"localhost:8000\", \"localhost:8001\", \"localhost:8002/subdir\"]
The default host(s) that can render your ReactPy components.
ReactPy will use these hosts in a round-robin fashion, allowing for easy distributed computing. This is typically useful for self-hosted applications.
You can use the
"},{"location":"reference/settings/#reactpy_prerender","title":"host
argument in your template tag to manually override this default.REACTPY_PRERENDER
","text":"Default:
False
Example Value(s):
True
Configures whether to pre-render your components via HTTP, which enables SEO compatibility and reduces perceived latency.
During pre-rendering, there are some key differences in behavior:
- Only the component's first paint is pre-rendered.
- All
connection
hooks will provide HTTP variants. - The component will be non-interactive until a WebSocket connection is formed.
- The component is re-rendered once a WebSocket connection is formed.
You can use the
"},{"location":"reference/settings/#stability-settings","title":"Stability Settings","text":""},{"location":"reference/settings/#reactpy_reconnect_interval","title":"prerender
argument in your template tag to manually override this default.REACTPY_RECONNECT_INTERVAL
","text":"Default:
750
Example Value(s):
100
,2500
,6000
Milliseconds between client reconnection attempts.
"},{"location":"reference/settings/#reactpy_reconnect_backoff_multiplier","title":"REACTPY_RECONNECT_BACKOFF_MULTIPLIER
","text":"Default:
1.25
Example Value(s):
1
,1.5
,3
On each reconnection attempt, the
REACTPY_RECONNECT_INTERVAL
will be multiplied by this value to increase the time between attempts.You can keep time between each reconnection the same by setting this to
"},{"location":"reference/settings/#reactpy_reconnect_max_interval","title":"1
.REACTPY_RECONNECT_MAX_INTERVAL
","text":"Default:
60000
Example Value(s):
10000
,25000
,900000
Maximum milliseconds between client reconnection attempts.
This allows setting an upper bound on how high
"},{"location":"reference/settings/#reactpy_reconnect_max_retries","title":"REACTPY_RECONNECT_BACKOFF_MULTIPLIER
can increase the time between reconnection attempts.REACTPY_RECONNECT_MAX_RETRIES
","text":"Default:
150
Example Value(s):
0
,5
,300
Maximum number of reconnection attempts before the client gives up.
"},{"location":"reference/settings/#reactpy_session_max_age","title":"REACTPY_SESSION_MAX_AGE
","text":"Default:
259200
Example Value(s):
0
,60
,96000
Maximum seconds a ReactPy component session is valid for. Invalid sessions are deleted during ReactPy clean up.
ReactPy sessions include data such as
*args
and**kwargs
passed into your{% component %}
template tag.Use
"},{"location":"reference/settings/#auto-clean-settings","title":"Auto-Clean Settings","text":""},{"location":"reference/settings/#reactpy_clean_interval","title":"0
to not store any session data.REACTPY_CLEAN_INTERVAL
","text":"Default:
604800
Example Value(s):
0
,3600
,86400
,None
Minimum seconds between ReactPy automatic clean up operations.
After a component disconnection, the server will perform a clean up if this amount of time has passed since the last clean up.
Set this value to
"},{"location":"reference/settings/#reactpy_clean_sessions","title":"None
to disable automatic clean up operations.REACTPY_CLEAN_SESSIONS
","text":"Default:
True
Example Value(s):
False
Configures whether ReactPy should clean up expired component sessions during automatic clean up operations.
"},{"location":"reference/settings/#reactpy_clean_user_data","title":"REACTPY_CLEAN_USER_DATA
","text":"Default:
True
Example Value(s):
False
Configures whether ReactPy should clean up orphaned user data during automatic clean up operations.
Typically, user data does not become orphaned unless the server crashes during a
"},{"location":"reference/template-tag/","title":"Template Tag","text":""},{"location":"reference/template-tag/#overview","title":"Overview","text":"User
delete operation.Django template tags can be used within your HTML templates to provide ReactPy features.
"},{"location":"reference/template-tag/#component","title":"Component","text":"This template tag can be used to insert any number of ReactPy components onto your page.
Each component loaded via this template tag will receive a dedicated WebSocket connection to the server.
my_template.html
See Interface{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n </body>\n</html>\n
Parameters
Name Type Description Defaultdotted_path
str
The dotted path to the component to render. N/A*args
Any
The positional arguments to provide to the component. N/Aclass
str | None
The HTML class to apply to the top-level component div.None
key
Any
Force the component's root node to use a specific key value. Usingkey
within a template tag is effectively useless.None
host
str | None
The host to use for ReactPy connections. If unset, the host will be automatically configured.Example values include:localhost:8000
,example.com
,example.com/subdir
None
prerender
str
If\"true\"
the component will pre-rendered, which enables SEO compatibility and reduces perceived latency.\"false\"
offline
str
The dotted path to a component that will be displayed if your root component loses connection to the server. Keep in mind, thisoffline
component will be non-interactive (hooks won't operate).\"\"
**kwargs
Any
The keyword arguments to provide to the component. N/A Do not use context variables for the component pathThe ReactPy component finder requires that your component path is a string.
Do not use Django template/context variables for the component path. Failure to follow this warning will result in render failures.
For example, do not do the following:
my_template.htmlviews.py<!-- This is good -->\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n\n<!-- This is bad -->\n{% component my_variable recipient=\"World\" %}\n
from django.shortcuts import render\n\n\ndef example_view(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_variable\": \"example_project.my_app.components.hello_world\"},\n )\n
Note: If you decide to not follow this warning, you will need to use the
Can I use multiple components on one page?register_component
function to manually register your components.You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use ReactPy will typically involve many components on one page.
my_template.html{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n <h1>{% component \"example_project.my_app.components.my_title\" %}</h1>\n <p>{% component \"example_project.my_app_2.components.goodbye_world\" class=\"bold small-font\" %}</p>\n{% component \"example_project.my_app_3.components.simple_button\" %}\n </body>\n</html>\n
Please note that components separated like this will not be able to interact with each other, except through database queries.
Additionally, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one component within your
Can I use positional arguments instead of keyword arguments?<body>
tag.You can use any combination of
my_template.htmlcomponents.py*args
/**kwargs
in your template tag.{% component \"example_project.my_app.components.frog_greeter\" 123 \"Mr. Froggles\" species=\"Grey Treefrog\" %}\n
Can I render components on a different server (distributed computing)?from reactpy import component\n\n\n@component\ndef frog_greeter(number, name, species=\"\"):\n return f\"Hello #{number}, {name} the {species}!\"\n
Yes! This is most commonly done through
my_template.htmlsettings.py:REACTPY_HOSTS
. However, you can use thehost
keyword to render components on a specific ASGI server....\n{% component \"example_project.my_app.components.do_something\" host=\"127.0.0.1:8001\" %}\n...\n
This configuration most commonly involves you deploying multiple instances of your project. But, you can also create dedicated Django project(s) that only render specific ReactPy components if you wish.
Here's a couple of things to keep in mind:
- If your host address are completely separate (
origin1.com != origin2.com
) you will need to configure CORS headers on your main application during deployment. - You will not need to register ReactPy WebSocket or HTTP paths on any applications that do not perform any component rendering.
- Your component will only be able to access your template tag's
*args
/**kwargs
if your applications share a common database.
This is most commonly done through
my_template.htmlsettings.py:REACTPY_PRERENDER
. However, you can use theprerender
keyword to pre-render a specific component.
How do I display something when the client disconnects?...\n{% component \"example_project.my_app.components.do_something\" prerender=\"true\" %}\n...\n
You can use the
my_template.htmloffline
keyword to display a specific component when the client disconnects from the server....\n{% component \"example_project.my_app.components.do_something\" offline=\"example_project.my_app.components.offline\" %}\n...\n
Note: The
"},{"location":"reference/template-tag/#pyscript-component","title":"PyScript Component","text":"offline
component will be non-interactive (hooks won't operate).This template tag can be used to insert any number of client-side ReactPy components onto your page.
By default, the only dependencies available are the Python standard library,
pyscript
,pyodide
,reactpy
core.Your PyScript component file requires a
def root()
component to function as the entry point.Pitfall
Your provided Python file is loaded directly into the client (web browser) as raw text, and ran using a PyScript interpreter. Be cautious about what you include in your Python file.
As a result of running client-side, Python packages within your local environment (such as those installed via
my_template.htmlhello_world.pypip install ...
) are not accessible within PyScript components.{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n\n<body>\n{% pyscript_component \"./example_project/my_app/components/hello_world.py\" %}\n</body>\n\n</html>\n
See Interfacefrom reactpy import component, html\n\n\n@component\ndef root():\n return html.div(\"Hello, World!\")\n
Parameters
Name Type Description Default*file_paths
str
File path to your client-side component. If multiple paths are provided, the contents are automatically merged. N/Ainitial
str | VdomDict | ComponentType
The initial HTML that is displayed prior to the PyScript component loads. This can either be a string containing raw HTML, areactpy.html
snippet, or a non-interactive component.\"\"
root
str
The name of the root component function.\"root\"
How do I execute JavaScript within PyScript components?PyScript components have the ability to directly execute standard library JavaScript using the
pyodide
js
module orpyscript
foreign function interface.The
root.pyjs
module has access to everything within the browser's JavaScript environment. Therefore, any global JavaScript functions loaded within your HTML<head>
can be called as well. However, be mindful of JavaScript load order!import js\nfrom reactpy import component, html\n\n\n@component\ndef root():\n\n def onClick(event):\n js.document.title = \"New window title\"\n\n return html.button({\"onClick\": onClick}, \"Click Me!\")\n
To import JavaScript modules in a fashion similar to
root.pymy_template.htmlimport {moment} from 'static/moment.js'
, you will need to configure your{% pyscript_setup %}
block to make the module available to PyScript. This module will be accessed withinpyscript.js_modules.*
. For more information, see the PyScript JS modules docs.from reactpy import component, html\n\n\n@component\ndef root():\n from pyscript.js_modules import moment\n\n return html.div(\n {\"id\": \"moment\"},\n \"Using the JavaScript package 'moment' to calculate time: \",\n moment.default().format(\"YYYY-MM-DD HH:mm:ss\"),\n )\n
Does my entire component need to be contained in one file?{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup extra_js='{\"/static/moment.js\":\"moment\"}' %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.root.py\" %}\n</body>\n\n</html>\n
Splitting a large file into multiple files is a common practice in software development.
However, PyScript components are run on the client browser. As such, they do not have access to your local development environment, and thus cannot
import
any local Python files.If your PyScript component file gets too large, you can declare multiple file paths instead. These files will automatically combined by ReactPy.
Here is how we recommend splitting your component into multiple files while avoiding local imports but retaining type hints.
my_template.htmlroot.pychild.py{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n\n<body>\n{% pyscript_component \"./example_project/my_app/components/root.py\"\n \"./example_project/my_app/components/child.py\" %}\n</body>\n\n</html>\n
from typing import TYPE_CHECKING\n\nfrom reactpy import component, html\n\nif TYPE_CHECKING:\n from .child import child_component\n\n\n@component\ndef root():\n return html.div(\"This text is from the root component.\", child_component())\n
How do I display something while the component is loading?from reactpy import component, html\n\n\n@component\ndef child_component():\n return html.div(\"This is a child component from a different file.\")\n
You can configure the
initial
keyword to display HTML while your PyScript component is loading.The value for
my_template.htmlinitial
is most commonly be a string containing raw HTML.<body>\n{% pyscript_component \"./example_project/my_app/components/root.py\" initial=\"<div> Loading ... </div>\" %}\n</body>\n
However, you can also insert a
my_template.htmlviews.pyreactpy.html
snippet or a non-interactive@component
via template context.<body>\n{% pyscript_component \"./example_project/my_app/components/root.py\" initial=my_initial_object %}\n</body>\n
Can I use a different name for my root component?from django.shortcuts import render\nfrom reactpy import html\n\n\ndef index(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_initial_object\": html.div(\"Loading ...\")},\n )\n
Yes, you can use the
my_template.htmlmain.pyroot
keyword to specify a different name for your root function.<body>\n{% pyscript_component \"./example_project/my_app/components/main.py\" root=\"main\" %}\n</body>\n
"},{"location":"reference/template-tag/#pyscript-setup","title":"PyScript Setup","text":"from reactpy import component, html\n\n\n@component\ndef main():\n return html.div(\"Hello, World!\")\n
This template tag configures the current page to be able to run
pyscript
.You can optionally use this tag to configure the current PyScript environment. For example, you can include a list of Python packages to automatically install within the PyScript environment.
my_template.html
See Interface{% load reactpy %}\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
Parameters
Name Type Description Default*extra_py
str
Dependencies that need to be loaded on the page for your PyScript components. Each dependency must be contained within it's own string and written in Python requirements file syntax. N/Aextra_js
str | dict
A JSON string or Python dictionary containing a vanilla JavaScript module URL and thename: str
to access it withinpyscript.js_modules.*
.\"\"
config
str | dict
A JSON string or Python dictionary containing PyScript configuration values.\"\"
How do I install additional Python dependencies?Dependencies must be available on
pypi
and declared in your{% pyscript_setup %}
block using Python requirements file syntax.These dependencies are automatically downloaded and installed into the PyScript client-side environment when the page is loaded.
my_template.html
How do I install additional Javascript dependencies?<head>\n <title>ReactPy</title>\n{% pyscript_setup \"dill==0.3.5\" \"markdown<=3.6.0\" \"nest_asyncio\" \"titlecase\" %}\n</head>\n
You can use the
my_template.htmlviews.pyextra_js
keyword to load additional JavaScript modules into your PyScript environment.{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup extra_js=my_extra_js_object %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.root.py\" %}\n</body>\n\n</html>\n
from django.shortcuts import render\nfrom django.templatetags.static import static\n\n\ndef index(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_extra_js_object\": {static(\"moment.js\"): \"moment\"}},\n )\n
The value for
my_template.htmlextra_js
is most commonly a Python dictionary, but JSON strings are also supported.
How do I modify the{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup extra_js='{\"/static/moment.js\":\"moment\"}' %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.root.py\" %}\n</body>\n\n</html>\n
pyscript
default configuration?You can modify the default PyScript configuration by providing a value to the
my_template.htmlconfig
keyword.<head>\n <title>ReactPy</title>\n{% pyscript_setup config='{\"experimental_create_proxy\":\"auto\"}' %}\n</head>\n
While this value is most commonly a JSON string, Python dictionary objects are also supported.
my_template.htmlviews.py<head>\n <title>ReactPy</title>\n{% pyscript_setup config=my_config_object %}\n</head>\n
"},{"location":"reference/utils/","title":"Utilities","text":""},{"location":"reference/utils/#overview","title":"Overview","text":"from django.shortcuts import render\n\n\ndef index(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_config_object\": {\"experimental_create_proxy\": \"auto\"}},\n )\n
Utility functions provide various miscellaneous functionality for advanced use cases.
Pitfall
Any utility functions not documented here are not considered part of the public API and may change without notice.
"},{"location":"reference/utils/#register-iframe","title":"Register Iframe","text":"This function is used register a view as an
iframe
with ReactPy.It is mandatory to use this function alongside
apps.pyview_to_iframe
.
See Interfacefrom django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.hello_world)\n
Parameters
Name Type Description Defaultview
Callable | View | str
The view to register. Can be a function or class based view, or a dotted path to a view. N/AReturns
Only use this withinNone
MyAppConfig.ready()
You should always call
"},{"location":"reference/utils/#register-component","title":"Register Component","text":"register_iframe
within a DjangoMyAppConfig.ready()
method. This ensures you will retain multiprocessing compatibility, such as with ASGI web server workers.This function is used register a root component with ReactPy.
Typically, this function is automatically called on all components contained within Django templates.
apps.py
See Interfacefrom django.apps import AppConfig\nfrom reactpy_django.utils import register_component\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_component(\"example_project.my_app.components.hello_world\")\n
Parameters
Name Type Description Defaultcomponent
ComponentConstructor | str
The component to register. Can be a component function or dotted path to a component. N/AReturns
Only use this withinNone
MyAppConfig.ready()
You should always call
Do I need to use this?register_component
within a DjangoMyAppConfig.ready()
method. This ensures you will retain multiprocessing compatibility, such as with ASGI web server workers.You typically will not need to use this function.
For security reasons, ReactPy requires all root components to be registered. However, all components contained within Django templates are automatically registered.
This function is commonly needed when you have configured your
"},{"location":"reference/utils/#django-query-postprocessor","title":"Django Query Postprocessor","text":"host
to a dedicated Django rendering application that doesn't have templates.This is the default postprocessor for the
use_query
hook.Since ReactPy is rendered within an
components.pymodels.pyasyncio
loop, this postprocessor is exists to prevent Django'sSynchronousOnlyException
by recursively prefetching fields within aModel
orQuerySet
. This prefetching step works to eliminate Django's lazy execution behavior.from example.models import TodoItem\nfrom reactpy import component\nfrom reactpy_django.hooks import use_query\nfrom reactpy_django.utils import django_query_postprocessor\n\n\ndef get_items():\n return TodoItem.objects.all()\n\n\n@component\ndef todo_list():\n # These postprocessor options are functionally equivalent to ReactPy-Django's default values\n item_query = use_query(\n get_items,\n postprocessor=django_query_postprocessor,\n postprocessor_kwargs={\"many_to_many\": True, \"many_to_one\": True},\n )\n\n return item_query.data\n
See Interfacefrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
Parameters
Name Type Description Defaultdata
QuerySet | Model
TheModel
orQuerySet
to recursively fetch fields from. N/Amany_to_many
bool
Whether or not to recursively fetchManyToManyField
relationships.True
many_to_one
bool
Whether or not to recursively fetchForeignKey
relationships.True
Returns
Type DescriptionQuerySet | Model
TheModel
orQuerySet
with all fields fetched."}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"about/changelog/","title":"Changelog","text":"The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
"},{"location":"about/changelog/#unreleased","title":"Unreleased","text":"- Nothing (yet)!
- Client-side Python components can now be rendered via the new
{% pyscript_component %}
template tag- You must first call the
{% pyscript_setup %}
template tag to load PyScript dependencies
- You must first call the
- Client-side components can be embedded into existing server-side components via
reactpy_django.components.pyscript_component
. - Tired of writing JavaScript? You can now write PyScript code that runs directly within client browser via the
reactpy_django.html.pyscript
element.- This is a viable substitution for most JavaScript code.
-
New syntax for
use_query
anduse_mutation
hooks. Here's a quick comparison of the changes:query = use_query(QueryOptions(thread_sensitive=True), get_items, foo=\"bar\") # Old\nquery = use_query(get_items, {\"foo\":\"bar\"}, thread_sensitive=True) # New\n\nmutation = use_mutation(MutationOptions(thread_sensitive=True), remove_item) # Old\nmutation = use_mutation(remove_item, thread_sensitive=True) # New\n
QueryOptions
andMutationOptions
have been removed. The value contained within these objects are now passed directly into the hook.
- Resolved a bug where Django-ReactPy would not properly detect
settings.py:DEBUG
.
- Python 3.12 compatibility
- Built-in cross-process communication mechanism via the
reactpy_django.hooks.use_channel_layer
hook. - Access to the root component's
id
via thereactpy_django.hooks.use_root_id
hook. - More robust control over ReactPy clean up tasks!
settings.py:REACTPY_CLEAN_INTERVAL
to control how often ReactPy automatically performs cleaning tasks.settings.py:REACTPY_CLEAN_SESSIONS
to control whether ReactPy should clean up expired sessions during automatic cleanups.settings.py:REACTPY_CLEAN_USER_DATA
to control whether ReactPy should clean up orphaned user data during automatic cleanups.python manage.py clean_reactpy
command to manually perform ReactPy clean up tasks.
- Simplified code for cascading deletion of user data.
- An \"offline component\" can now be displayed when the client disconnects from the server.
- URL router now supports a
*
wildcard to create default routes.
- Built-in Single Page Application (SPA) support!
reactpy_django.router.django_router
can be used to render your Django application as a SPA.
- SEO compatible rendering!
settings.py:REACTPY_PRERENDER
can be set toTrue
to make components pre-render by default.- Or, you can enable it on individual components via the template tag:
{% component \"...\" prerender=\"True\" %}
.
- New
view_to_iframe
feature!reactpy_django.components.view_to_iframe
uses an<iframe>
to render a Django view.reactpy_django.utils.register_iframe
tells ReactPy which viewsview_to_iframe
can use.
- New Django
User
related features!reactpy_django.hooks.use_user
can be used to access the current user.reactpy_django.hooks.use_user_data
provides a simplified interface for storing user key-value data.reactpy_django.decorators.user_passes_test
is inspired by the equivalent Django decorator, but ours works with ReactPy components.settings.py:REACTPY_AUTO_RELOGIN
will cause component WebSocket connections to automatically re-login users that are already authenticated. This is useful to continuously updatelast_login
timestamps and refresh the Django login session.
- Renamed undocumented utility function
ComponentPreloader
toRootComponentFinder
. - It is now recommended to call
as_view()
when usingview_to_component
orview_to_iframe
with Class Based Views. - For thread safety,
thread_sensitive=True
has been enabled in allsync_to_async
functions where ORM queries are possible. reactpy_django.hooks.use_mutation
now has a__call__
method. So rather than writingmy_mutation.execute(...)
, you can now writemy_mutation(...)
.
- The
compatibility
argument onreactpy_django.components.view_to_component
is deprecated.- Use
view_to_iframe
as a replacement.
- Use
reactpy_django.components.view_to_component
usage as a decorator is deprecated.- Check the docs on how to use
view_to_component
as a function instead.
- Check the docs on how to use
reactpy_django.decorators.auth_required
is deprecated.- Use
reactpy_django.decorators.user_passes_test
instead. - An equivalent to
auth_required
's default is@user_passes_test(lambda user: user.is_active)
.
- Use
- Fixed a bug where exception stacks would not print on failed component renders.
- Warning W018 (
Suspicious position of 'reactpy_django' in INSTALLED_APPS
) has been added.
- The default postprocessor can now disabled by setting
REACTPY_DEFAULT_QUERY_POSTPROCESSOR
toNone
. - Massive overhaul of docs styling.
- More customization for reconnection behavior through new settings!
REACTPY_RECONNECT_INTERVAL
REACTPY_RECONNECT_MAX_INTERVAL
REACTPY_RECONNECT_MAX_RETRIES
REACTPY_RECONNECT_BACKOFF_MULTIPLIER
- ReactPy-Django docs are now version controlled via mike!
- Bumped the minimum ReactPy version to
1.0.2
. - Prettier WebSocket URLs for components that do not have sessions.
- Template tag will now only validate
args
/kwargs
ifsettings.py:DEBUG
is enabled. - Bumped the minimum
@reactpy/client
version to0.3.1
- Use TypeScript instead of JavaScript for this repository.
- Bumped the minimum Django version to
4.2
.
ReactPy-Django will continue bumping minimum Django requirements to versions that increase async support.
This \"latest-only\" trend will continue until Django has all async features that ReactPy benefits from. After this point, ReactPy-Django will begin supporting all maintained Django versions.
"},{"location":"about/changelog/#removed_1","title":"Removed","text":"settings.py:REACTPY_RECONNECT_MAX
is removed. See the docs for the newREACTPY_RECONNECT_*
settings.
- Distributed Computing: ReactPy components can now optionally be rendered by a completely separate server!
REACTPY_DEFAULT_HOSTS
setting can round-robin a list of ReactPy rendering hosts.host
argument has been added to thecomponent
template tag to force components to render on a specific host.
reactpy_django.utils.register_component
function can manually register root components.- Useful if you have dedicated ReactPy rendering application(s) that do not use HTML templates.
- ReactPy will now provide a warning if your HTTP URLs are not on the same prefix as your WebSockets.
- Cleaner logging output for auto-detected ReactPy root components.
reactpy_django.REACTPY_WEBSOCKET_PATH
is deprecated. The identical replacement isREACTPY_WEBSOCKET_ROUTE
.settings.py:REACTPY_WEBSOCKET_URL
is deprecated. The similar replacement isREACTPY_URL_PREFIX
.
- Warning W007 (
REACTPY_WEBSOCKET_URL doesn't end with a slash
) has been removed. ReactPy now automatically handles slashes. - Warning W008 (
REACTPY_WEBSOCKET_URL doesn't start with an alphanumeric character
) has been removed. ReactPy now automatically handles this scenario. - Error E009 (
channels is not in settings.py:INSTALLED_APPS
) has been removed. Newer versions ofchannels
do not require installation viaINSTALLED_APPS
to receive an ASGI web server.
- ReactPy WebSocket will now decode messages via
orjson
resulting in an ~6% overall performance improvement. - Built-in
asyncio
event loops are now patched vianest_asyncio
, resulting in an ~10% overall performance improvement. This has no performance impact if you are running your web server withuvloop
.
- Fix bug where
REACTPY_WEBSOCKET_URL
always generates a warning if unset. - Fixed bug on Windows where
assert f is self._write_fut
would be raised byuvicorn
whenREACTPY_BACKHAUL_THREAD = True
. - Fixed bug on Windows where rendering behavior would be jittery with
daphne
whenREACTPY_BACKHAUL_THREAD = True
.
- Additional system checks for ReactPy misconfigurations.
REACTPY_BACKHAUL_THREAD
now defaults toFalse
.
- Added system checks for a variety of common ReactPy misconfigurations.
REACTPY_BACKHAUL_THREAD
setting to enable/disable threading behavior.
- If using
settings.py:REACTPY_DATABASE
,reactpy_django.database.Router
must now be registered insettings.py:DATABASE_ROUTERS
. - By default, ReactPy will now use a backhaul thread to increase performance.
- Minimum Python version required is now
3.9
- A thread-safe cache is no longer required.
- Template tag exception details are now rendered on the webpage when
settings.py:DEBUG
is enabled.
- Prevent exceptions within the
component
template tag from causing the whole template to fail to render.
- Added warning if poor system/cache/database performance is detected while in
DEBUG
mode. - Added
REACTPY_AUTH_BACKEND
setting to allow for custom authentication backends.
- Using
SessionMiddlewareStack
is now optional. - Using
AuthMiddlewareStack
is now optional.
use_query
now supports async functions.use_mutation
now supports async functions.reactpy_django.types.QueryOptions.thread_sensitive
option to customize how sync queries are executed.reactpy_django.hooks.use_mutation
now acceptsreactpy_django.types.MutationOptions
option to customize how mutations are executed.
- The
mutate
argument onreactpy_django.hooks.use_mutation
has been renamed tomutation
.
- Fix bug where ReactPy utilizes Django's default cache timeout, which can prematurely expire the component cache.
reactpy-django
database entries are no longer cleaned during Django application startup. Instead, it will occur on webpage loads ifREACTPY_RECONNECT_MAX
seconds has elapsed since the last cleaning.
django-idom
has been renamed toreactpy-django
! Please note that all references to the wordidom
in your code should be changed toreactpy
. See the docs for more details.
This is Django-IDOM's biggest update yet!
To upgrade from previous version you will need to...
- Install
django-idom >= 3.0.0
- Run
idom rewrite-keys <DIR>
andidom rewrite-camel-case-props <DIR>
to update youridom.html.*
calls to the new syntax - Run
python manage.py migrate
to create the new Django-IDOM database entries
- The
idom
client will automatically configure itself to debug mode depending onsettings.py:DEBUG
. use_connection
hook for returning the browser's activeConnection
.IDOM_CACHE
is now configurable withinsettings.py
to whatever cache name you wish.
- It is now mandatory to run
manage.py migrate
after installing IDOM. - Bumped the minimum IDOM version to 1.0.0. Due to IDOM 1.0.0,
idom.html.*
...- HTML properties can now be
snake_case
. For exampleclassName
now becomesclass_name
. key=...
is now declared within the propsdict
(rather than as akwarg
).
- HTML properties can now be
- The
component
template tag now supports both positional and keyword arguments. - The
component
template tag now supports non-serializable arguments. IDOM_WS_MAX_RECONNECT_TIMEOUT
setting has been renamed toIDOM_RECONNECT_MAX
.
django_idom.hooks.use_websocket
has been removed. The similar replacement isdjango_idom.hooks.use_connection
.django_idom.types.IdomWebsocket
has been removed. The similar replacement isdjango_idom.types.Connection
.settings.py:CACHE['idom']
is no longer used by default. The name of the cache back-end must now be specified with theIDOM_CACHE
setting.
view_to_component
will now retain the contents of a<head>
tag when rendering.- React client is now set to
production
rather thandevelopment
. use_query
will now utilizefield.related_name
when postprocessing many-to-one relationships.
- Fixed a potential method of component template tag argument spoofing.
- Exception information will no longer be displayed on the page, based on the value of
settings.py:DEBUG
.
- Fixed bug where
use_query
would not recursively fetch many-to-one relationships. - IDOM preloader will now print out the exception stack when failing to import a module.
- Add
options: QueryOptions
parameter touse_query
to allow for configuration of this hook.
- By default,
use_query
will recursively prefetch all many-to-many or many-to-one relationships to preventSynchronousOnlyOperation
exceptions.
django_idom.hooks._fetch_lazy_fields
has been deleted. The equivalent replacement isdjango_idom.utils.django_query_postprocessor
.
- Minimum
channels
version is now4.0.0
.
- Change type hint on
view_to_component
callable to haverequest
argument be optional. - Change type hint on
view_to_component
to represent it as a decorator with parenthesis (such as@view_to_component(compatibility=True)
)
- Add note to docs about potential information exposure via
view_to_component
when usingcompatibility=True
.
- Ability to use
key=...
parameter on all prefabricated components.
use_origin
hook for returning the browser'slocation.origin
.
view_to_component
now returns aCallable
, instead of directly returning aComponent
. Check the docs for new usage info.use_mutation
anduse_query
will now log any query failures.
- Allow
use_mutation
to haverefetch=None
, as the docs suggest is possible. use_query
will now prefetch all fields to preventSynchronousOnlyOperation
exceptions.view_to_component
,django_css
, anddjango_js
type hints will now display like normal functions.- IDOM preloader no longer attempts to parse commented out IDOM components.
- Tests are now fully functional on Windows
auth_required
decorator to prevent your components from rendering to unauthenticated users.use_query
hook for fetching database values.use_mutation
hook for modifying database values.view_to_component
utility to convert legacy Django views to IDOM components.
- Bumped the minimum IDOM version to 0.40.2
- Testing suite now uses
playwright
instead ofselenium
- IDOM preloader is no longer sensitive to whitespace within template tags.
django_css
anddjango_js
components to defer loading CSS & JS files until needed.
- Bumped the minimum IDOM version to 0.39.0
- Django specific hooks!
use_websocket
,use_scope
, anduse_location
are now available within thedjango_idom.hooks
module. - Documentation has been placed into a formal docs webpage.
- Logging for when a component fails to import, or if no components were found within Django.
idom_component
template tag has been renamed tocomponent
- Bumped the minimum IDOM version to 0.38.0
websocket
parameter for components has been removed. Functionally, it is replaced withdjango_idom.hooks.use_websocket
.
- Bumped the minimum IDOM version to 0.37.2
- ModuleNotFoundError: No module named
idom.core.proto
caused by IDOM 0.37.2
- Bumped the minimum IDOM version to 0.37.1
- Bumped the minimum IDOM version to 0.36.3
- Ability to declare the HTML class of the top-level component
div
name = ...
parameter to IDOM HTTP paths for use withdjango.urls.reverse()
- Cache versioning to automatically invalidate old web module files from the cache back-end
- Automatic pre-population of the IDOM component registry
- Type hinting for
IdomWebsocket
- Fetching web modules from disk and/or cache is now fully async
- Static files are now contained within a
django_idom/
parent folder - Upgraded IDOM to version
0.36.0
- Minimum Django version required is now
4.0
- Minimum Python version required is now
3.8
IDOM_WEB_MODULES_PATH
has been replaced with Djangoinclude(...)
IDOM_WS_MAX_RECONNECT_DELAY
has been renamed toIDOM_WS_MAX_RECONNECT_TIMEOUT
idom_web_modules
cache back-end has been renamed toidom
- Increase test timeout values to prevent false positives
- Windows compatibility for building Django-IDOM
- Fixed potential directory traversal attack on the IDOM web modules URL
- Support for IDOM within the Django
You will need to set up a Python environment to develop ReactPy-Django.
Note
Looking to contribute features that are not Django specific?
Everything within the
"},{"location":"about/code/#creating-an-environment","title":"Creating an environment","text":"reactpy-django
repository must be specific to Django integration. Check out the ReactPy Core documentation to contribute general features such as components, hooks, and events.If you plan to make code changes to this repository, you will need to install the following dependencies first:
- Python 3.9+
- Git
Once done, you should clone this repository:
git clone https://github.com/reactive-python/reactpy-django.git\ncd reactpy-django\n
Then, by running the command below you can install the dependencies needed to run the ReactPy-Django development environment.
pip install -r requirements.txt --upgrade --verbose\n
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:
- When
pip install
is run on thereactpy-django
package. - Every time
python manage.py ...
ornox ...
is run
Note
This repository uses Nox 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:
nox -t test\n
Or, if you want to run the tests in the background:
"},{"location":"about/code/#running-django-tests","title":"Running Django tests","text":"nox -t test -- --headless\n
If you want to only run our Django tests in your current environment, you can use the following command:
"},{"location":"about/code/#running-django-test-web-server","title":"Running Django test web server","text":"cd tests\npython manage.py test\n
If you want to manually run the Django test application, you can use the following command:
"},{"location":"about/code/#creating-a-pull-request","title":"Creating a pull request","text":"cd tests\npython manage.py runserver\n
Now, you can create/modify the ReactPy-Django source code, and Pull Request (PR) your changes to our GitHub repository.
To learn how to create GitHub PRs, click here.
"},{"location":"about/docs/","title":"Docs","text":""},{"location":"about/docs/#overview","title":"Overview","text":"You will need to set up a Python environment to create, test, and preview docs changes.
"},{"location":"about/docs/#modifying-docs","title":"Modifying Docs","text":"If you plan to make changes to this documentation, you will need to install the following dependencies first:
- Python 3.9+
- Git
Once done, you should clone this repository:
git clone https://github.com/reactive-python/reactpy-django.git\ncd reactpy-django\n
Then, by running the command below you can:
- Install an editable version of the documentation
- Self-host a test server for the documentation
pip install -r requirements.txt --upgrade\n
Finally, to verify that everything is working properly, you can manually run the docs preview web server.
cd docs\nmkdocs serve\n
Navigate to
"},{"location":"about/docs/#github-pull-request","title":"GitHub Pull Request","text":"http://127.0.0.1:8000
to view a preview of the documentation.Now, you can create/modify the ReactPy-Django source code, and Pull Request (PR) your changes to our GitHub repository.
To learn how to create GitHub PRs, click here.
"},{"location":"about/license/","title":"License","text":""},{"location":"about/license/#the-mit-license-mit","title":"The MIT License (MIT)","text":""},{"location":"about/license/#copyright-c-reactive-python-and-affiliates","title":"Copyright (c) Reactive Python and affiliates.","text":"Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"},{"location":"learn/add-reactpy-to-a-django-project/","title":"Add ReactPy to a Django Project","text":""},{"location":"learn/add-reactpy-to-a-django-project/#overview","title":"Overview","text":"If you want to add some interactivity to your existing Django project, you don't have to rewrite it in ReactPy. Use ReactPy-Django to add ReactPy to your existing stack, and render interactive components anywhere.
Note
These docs assumes you have already created a Django project, which involves creating and installing at least one Django app.
If do not have a Django project, check out this 9 minute YouTube tutorial created by IDG TECHtalk.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-1-install-from-pypi","title":"Step 1: Install from PyPI","text":"Run the following command to install
reactpy-django
in your Python environment.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-2-configure-settingspy","title":"Step 2: Configurepip install reactpy-django\n
settings.py
","text":"Add
settings.py\"reactpy_django\"
toINSTALLED_APPS
in yoursettings.py
file.
Enable ASGI and Django Channels (Required)INSTALLED_APPS = [\n ...,\n \"reactpy_django\",\n]\n
ReactPy-Django requires Django ASGI and Django Channels WebSockets.
If you have not enabled ASGI on your Django project yet, here is a summary of the
django
andchannels
installation docs:- Install
channels[daphne]
-
Add
\"daphne\"
toINSTALLED_APPS
.INSTALLED_APPS = [\n \"daphne\",\n ...,\n]\n
-
Set your
ASGI_APPLICATION
variable.ASGI_APPLICATION = \"example_project.asgi.application\"\n
ReactPy's has additional configuration available to fit a variety of use cases.
See the ReactPy settings documentation to learn more.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-3-configure-urlspy","title":"Step 3: Configureurls.py
","text":"Add ReactPy HTTP paths to your
urls.pyurlpatterns
in yoururls.py
file.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-4-configure-asgipy","title":"Step 4: Configurefrom django.urls import include, path\n\nurlpatterns = [\n ...,\n path(\"reactpy/\", include(\"reactpy_django.http.urls\")),\n]\n
asgi.py
","text":"Register ReactPy's WebSocket using
asgi.pyREACTPY_WEBSOCKET_ROUTE
in yourasgi.py
file.
Addimport os\n\nfrom django.core.asgi import get_asgi_application\n\n# Ensure DJANGO_SETTINGS_MODULE is set properly based on your project name!\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"example_project.settings\")\n\n# Fetch ASGI application before importing dependencies that require ORM models.\ndjango_asgi_app = get_asgi_application()\n\n\nfrom channels.routing import ProtocolTypeRouter, URLRouter # noqa: E402\nfrom reactpy_django import REACTPY_WEBSOCKET_ROUTE # noqa: E402\n\napplication = ProtocolTypeRouter(\n {\n \"http\": django_asgi_app,\n \"websocket\": URLRouter([REACTPY_WEBSOCKET_ROUTE]),\n }\n)\n
AuthMiddlewareStack
(Optional)There are many situations where you need to access the Django
User
orSession
objects within ReactPy components. For example, if you want to:- Access the
User
that is currently logged in - Access Django's
Session
object - Login or logout the current
User
In these situations will need to ensure you are using
AuthMiddlewareStack
.
Where is myfrom channels.auth import AuthMiddlewareStack # noqa: E402\n\napplication = ProtocolTypeRouter(\n {\n \"http\": django_asgi_app,\n \"websocket\": AuthMiddlewareStack(URLRouter([REACTPY_WEBSOCKET_ROUTE])),\n }\n)\n
asgi.py
?If you do not have an
"},{"location":"learn/add-reactpy-to-a-django-project/#step-5-run-database-migrations","title":"Step 5: Run database migrations","text":"asgi.py
, follow thechannels
installation guide.Run Django's
migrate
command to initialize ReactPy-Django's database table.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-6-check-your-configuration","title":"Step 6: Check your configuration","text":"python manage.py migrate\n
Run Django's
check
command to verify if ReactPy was set up correctly.
"},{"location":"learn/add-reactpy-to-a-django-project/#step-7-create-your-first-component","title":"Step 7: Create your first component","text":"python manage.py check\n
The next step will show you how to create your first ReactPy component.
Prefer a quick summary? Read the At a Glance section below.
At a Glance
my_app/components.py
You will need a file to define your ReactPy components. We recommend creating a
components.py
file within your chosen Django app to start out. Within this file, we will create a simplehello_world
component.from reactpy import component, html\n\n@component\ndef hello_world(recipient: str):\n return html.h1(f\"Hello {recipient}!\")\n
my_app/templates/my_template.html
In your Django app's HTML template, you can now embed your ReactPy component using the
component
template tag. Within this tag, you will need to type in the dotted path to the component.Additionally, you can pass in
args
andkwargs
into your component function. After reading the code below, pay attention to how the function definition forhello_world
(from the previous example) accepts arecipient
argument.
"},{"location":"learn/your-first-component/","title":"Your First Component","text":""},{"location":"learn/your-first-component/#overview","title":"Overview","text":"{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n </body>\n</html>\n
Components are one of the core concepts of ReactPy. They are the foundation upon which you build user interfaces (UI), which makes them the perfect place to start your journey!
Note
If you have reached this point, you should have already installed ReactPy-Django through the previous steps.
"},{"location":"learn/your-first-component/#selecting-a-django-app","title":"Selecting a Django App","text":"You will now need to pick at least one Django app to start using ReactPy-Django on.
For the following examples, we will assume the following:
- You have a Django app named
my_app
, which was created by Django'sstartapp
command. - You have placed
my_app
directly into your Django project folder (./example_project/my_app
). This is common for small projects.
ReactPy-Django has no project structure requirements. Organize everything as you wish, just like any Django project.
"},{"location":"learn/your-first-component/#defining-a-component","title":"Defining a component","text":"You will need a file to start creating ReactPy components.
We recommend creating a
components.py
file within your chosen Django app to start out. For this example, the file path will look like this:./example_project/my_app/components.py
.Within this file, you can define your component functions using ReactPy's
components.py@component
decorator.
What should I name my ReactPy files and functions?from reactpy import component, html\n\n@component\ndef hello_world(recipient: str):\n return html.h1(f\"Hello {recipient}!\")\n
You have full freedom in naming/placement of your files and functions.
We recommend creating a
components.py
for small Django apps. If your app has a lot of components, you should consider breaking them apart into individual modules such ascomponents/navbar.py
.Ultimately, components are referenced by Python dotted path in
What does the decorator actually do?my_template.html
(see next step). This path must be valid to Python'simportlib
.While not all components need to be decorated, there are a few features this decorator adds to your components.
- The ability to be used as a root component.
- The decorator is required for any component that you want to reference in your Django templates (see next step).
- The ability to use hooks.
- The decorator is required on any component where hooks are defined.
- Scoped failures.
- If a decorated component generates an exception, then only that one component will fail to render.
In your Django app's HTML template, you can now embed your ReactPy component using the
{% component %}
template tag. Within this tag, you will need to type in the dotted path to the component.Additionally, you can pass in
my_template.htmlargs
andkwargs
into your component function. After reading the code below, pay attention to how the function definition forhello_world
(from the previous step) accepts arecipient
argument.
Do not use context variables for the component path{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n </body>\n</html>\n
The ReactPy component finder requires that your component path is a string.
Do not use Django template/context variables for the component path. Failure to follow this warning will result in render failures.
For example, do not do the following:
my_template.htmlviews.py<!-- This is good -->\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n\n<!-- This is bad -->\n{% component my_variable recipient=\"World\" %}\n
from django.shortcuts import render\n\n\ndef example_view(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_variable\": \"example_project.my_app.components.hello_world\"},\n )\n
Note: If you decide to not follow this warning, you will need to use the
Can I use multiple components on one page?register_component
function to manually register your components.You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use ReactPy will typically involve many components on one page.
my_template.html{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n <h1>{% component \"example_project.my_app.components.my_title\" %}</h1>\n <p>{% component \"example_project.my_app_2.components.goodbye_world\" class=\"bold small-font\" %}</p>\n{% component \"example_project.my_app_3.components.simple_button\" %}\n </body>\n</html>\n
Please note that components separated like this will not be able to interact with each other, except through database queries.
Additionally, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one component within your
Where is my templates folder?<body>
tag.If you do not have a
"},{"location":"learn/your-first-component/#setting-up-a-django-view","title":"Setting up a Django view","text":"./templates/
folder in your Django app, you can simply create one! Keep in mind, templates within this folder will not be detected by Django unless you add the corresponding Django app tosettings.py:INSTALLED_APPS
.Within your Django app's
views.pyviews.py
file, you will need to create a view function to render the HTML templatemy_template.html
(from the previous step).from django.shortcuts import render\n\n\ndef index(request):\n return render(request, \"my_template.html\")\n
We will add this new view into your
urls.pyurls.py
and define what URL it should be accessible at.
Which urls.py do I add my views to?from django.urls import path\nfrom example import views\n\nurlpatterns = [\n path(\"example/\", views.index),\n]\n
For simple Django projects, you can easily add all of your views directly into the Django project's
urls.py
. However, as you start increase your project's complexity you might end up with way too much within one file.Once you reach that point, we recommend creating an individual
urls.py
within each of your Django apps.Then, within your Django project's
"},{"location":"learn/your-first-component/#viewing-your-component","title":"Viewing your component","text":"urls.py
you will use Django'sinclude
function to link it all together.To test your new Django view, run the following command to start up a development web server.
python manage.py runserver\n
Now you can navigate to your Django project URL that contains a ReactPy component, such as
http://127.0.0.1:8000/example/
(from the previous step).If you copy-pasted our example component, you will now see your component display \"Hello World\".
Do not usemanage.py runserver
for productionThis command is only intended for development purposes. For production deployments make sure to read Django's documentation.
"},{"location":"learn/your-first-component/#learn-more","title":"Learn more","text":"Congratulations! If you followed the previous steps, you have now created a \"Hello World\" component using ReactPy-Django!
Deep Dive
The docs you are reading only covers our Django integration. To learn more, check out one of the following links:
- ReactPy-Django Feature Reference
- ReactPy Core Documentation
- Ask Questions on Discord
Additionally, the vast majority of tutorials/guides you find for ReactJS can be applied to ReactPy.
"},{"location":"reference/components/","title":"Components","text":""},{"location":"reference/components/#overview","title":"Overview","text":"We supply some pre-designed that components can be used to help simplify development.
"},{"location":"reference/components/#pyscript-component","title":"PyScript Component","text":"This allows you to embedded any number of client-side PyScript components within traditional ReactPy components.
By default, the only dependencies available are the Python standard library,
pyscript
,pyodide
,reactpy
core.Your PyScript component file requires a
components.pyroot.pymy_template.htmldef root()
component to function as the entry point.from reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n \"This text is from my server-side component\",\n pyscript_component(\"./example_project/my_app/components/root.py\"),\n )\n
from reactpy import component, html\n\n\n@component\ndef root():\n return html.div(\"This text is from my client-side component\")\n
See Interface{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.server_side_component\" %}\n</body>\n\n</html>\n
Parameters
Name Type Description Default*file_paths
str
File path to your client-side component. If multiple paths are provided, the contents are automatically merged. N/Ainitial
str | VdomDict | ComponentType
The initial HTML that is displayed prior to the PyScript component loads. This can either be a string containing raw HTML, areactpy.html
snippet, or a non-interactive component.\"\"
root
str
The name of the root component function.\"root\"
You must callpyscript_setup
in your Django template before using this tag!This requires using of the
my_template.html{% pyscript_setup %}
template tag to initialize PyScript on the client.
How do I execute JavaScript within PyScript components?{% load reactpy %}\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
PyScript components have the ability to directly execute standard library JavaScript using the
pyodide
js
module orpyscript
foreign function interface.The
root.pyjs
module has access to everything within the browser's JavaScript environment. Therefore, any global JavaScript functions loaded within your HTML<head>
can be called as well. However, be mindful of JavaScript load order!import js\nfrom reactpy import component, html\n\n\n@component\ndef root():\n\n def onClick(event):\n js.document.title = \"New window title\"\n\n return html.button({\"onClick\": onClick}, \"Click Me!\")\n
To import JavaScript modules in a fashion similar to
root.pymy_template.htmlimport {moment} from 'static/moment.js'
, you will need to configure your{% pyscript_setup %}
block to make the module available to PyScript. This module will be accessed withinpyscript.js_modules.*
. For more information, see the PyScript JS modules docs.from reactpy import component, html\n\n\n@component\ndef root():\n from pyscript.js_modules import moment\n\n return html.div(\n {\"id\": \"moment\"},\n \"Using the JavaScript package 'moment' to calculate time: \",\n moment.default().format(\"YYYY-MM-DD HH:mm:ss\"),\n )\n
Does my entire component need to be contained in one file?{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup extra_js='{\"/static/moment.js\":\"moment\"}' %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.root.py\" %}\n</body>\n\n</html>\n
Splitting a large file into multiple files is a common practice in software development.
However, PyScript components are run on the client browser. As such, they do not have access to your local development environment, and thus cannot
import
any local Python files.If your PyScript component file gets too large, you can declare multiple file paths instead. These files will automatically combined by ReactPy.
Here is how we recommend splitting your component into multiple files while avoiding local imports but retaining type hints.
components.pyroot.pychild.pyfrom reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript_component(\n \"./example_project/my_app/components/root.py\",\n \"./example_project/my_app/components/child.py\",\n ),\n )\n
from typing import TYPE_CHECKING\n\nfrom reactpy import component, html\n\nif TYPE_CHECKING:\n from .child import child_component\n\n\n@component\ndef root():\n return html.div(\"This text is from the root component.\", child_component())\n
How do I display something while the component is loading?from reactpy import component, html\n\n\n@component\ndef child_component():\n return html.div(\"This is a child component from a different file.\")\n
You can configure the
initial
keyword to display HTML while your PyScript component is loading.The value for
components.pyinitial
is most commonly be areactpy.html
snippet or a non-interactive@component
.from reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript_component(\n \"./example_project/my_app/components/root.py\",\n initial=html.div(\"Loading ...\"),\n ),\n )\n
However, you can also use a string containing raw HTML.
components.py
Can I use a different name for my root component?from reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript_component(\n \"./example_project/my_app/components/root.py\",\n initial=\"<div> Loading ... </div>\",\n ),\n )\n
Yes, you can use the
components.pymain.pyroot
keyword to specify a different name for your root function.from reactpy import component, html\nfrom reactpy_django.components import pyscript_component\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript_component(\n \"./example_project/my_app/components/main.py\",\n root=\"main\",\n ),\n )\n
"},{"location":"reference/components/#view-to-component","title":"View To Component","text":"from reactpy import component, html\n\n\n@component\ndef main():\n return html.div(\"Hello, World!\")\n
Automatically convert a Django view into a component.
At this time, this works best with static views with no interactivity.
Compatible with sync or async Function Based Views and Class Based Views.
components.pyviews.pyfrom reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\nhello_world_component = view_to_component(views.hello_world)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_component(),\n )\n
See Interfacefrom django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
Parameters
Name Type Description Defaultview
Callable | View | str
The view to convert, or the view's dotted path as a string. N/Atransforms
Sequence[Callable[[VdomDict], Any]]
A list of functions that transforms the newly generated VDOM. The functions will be called on each VDOM node.tuple
strict_parsing
bool
IfTrue
, an exception will be generated if the HTML does not perfectly adhere to HTML5.True
Returns
Type Descriptionconstructor
A function that takesrequest, *args, key, **kwargs
and returns a ReactPy component. Note that*args
and**kwargs
are directly provided to your view. Existing limitationsThere are currently several limitations of using
view_to_component
that may be resolved in a future version.- 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
<a href='example/'></a>
) click events.
Class Based Views are accepted by
view_to_component
as an argument.Calling
components.pyviews.pyas_view()
is optional, but recommended.from reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\nhello_world_component = view_to_component(views.HelloWorld.as_view())\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_component(),\n )\n
How do I providefrom django.http import HttpResponse\nfrom django.views import View\n\n\nclass HelloWorld(View):\n def get(self, request):\n return HttpResponse(\"Hello World!\")\n
request
,args
, andkwargs
to a converted view?This component accepts
components.pyviews.pyrequest
,*args
, and**kwargs
arguments, which are sent to your provided view.from django.http import HttpRequest\nfrom reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\nhello_world_component = view_to_component(views.hello_world)\n\n\n@component\ndef my_component():\n request = HttpRequest()\n request.method = \"GET\"\n\n return html.div(\n hello_world_component(\n request, # This request object is optional.\n \"value_1\",\n \"value_2\",\n kwarg1=\"abc\",\n kwarg2=\"123\",\n ),\n )\n
How do I customize this component's behavior?from django.http import HttpResponse\n\n\ndef hello_world(request, arg1, arg2, kwarg1=None, kwarg2=None):\n return HttpResponse(f\"Hello World! {arg1} {arg2} {kwarg1} {kwarg2}\")\n
This component accepts arguments that can be used to customize its behavior.
Below are all the arguments that can be used.
strict_parsing
By default, an exception will be generated if your view's HTML does not perfectly adhere to HTML5.
However, there are some circumstances where you may not have control over the original HTML, so you may be unable to fix it. Or you may be relying on non-standard HTML tags such as
<my-tag> Hello World </my-tag>
.In these scenarios, you may want to rely on best-fit parsing by setting the
components.pyviews.pystrict_parsing
parameter toFalse
. This useslibxml2
recovery algorithm, which is designed to be similar to how web browsers would attempt to parse non-standard or broken HTML.from reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\nhello_world_component = view_to_component(views.hello_world)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_component(),\n )\n
from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
transforms
After your view has been turned into VDOM (python dictionaries),
view_to_component
will call yourtransforms
functions on every VDOM node.This allows you to modify your view prior to rendering.
For example, if you are trying to modify the text of a node with a certain
components.pyviews.pyid
, you can create a transform like such:from reactpy import component, html\nfrom reactpy_django.components import view_to_component\n\nfrom . import views\n\n\ndef example_transform(vdom):\n attributes = vdom.get(\"attributes\")\n if attributes and attributes.get(\"id\") == \"hello-world\":\n vdom[\"children\"][0] = \"Farewell World!\"\n\n\nhello_world_component = view_to_component(\n views.hello_world, transforms=[example_transform]\n)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_component(),\n )\n
"},{"location":"reference/components/#view-to-iframe","title":"View To Iframe","text":"from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse('<div id=\"hello-world\"> Hello World! </div>')\n
Automatically convert a Django view into an
iframe
element.The contents of this
iframe
is handled entirely by traditional Django view rendering. While this solution is compatible with more views thanview_to_component
, it comes with different limitations.Compatible with sync or async Function Based Views and Class Based Views.
components.pyviews.pyapps.pyfrom reactpy import component, html\nfrom reactpy_django.components import view_to_iframe\n\nfrom . import views\n\nhello_world_iframe = view_to_iframe(views.hello_world)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_iframe(),\n )\n
from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
See Interfacefrom django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.hello_world)\n
Parameters
Name Type Description Defaultview
Callable | View | str
The view function or class to convert. N/Aextra_props
Mapping[str, Any] | None
Additional properties to add to theiframe
element.None
Returns
Type Descriptionconstructor
A function that takes*args, key, **kwargs
and returns a ReactPy component. Note that*args
and**kwargs
are directly provided to your view. Existing limitationsThere are currently several limitations of using
view_to_iframe
that may be resolved in a future version.- No built-in method of signalling events back to the parent component.
- All provided
*args
and*kwargs
must be serializable values, since they are encoded into the URL. - The
iframe
will always load after the parent component. - CSS styling for
iframe
elements tends to be awkward/difficult.
Class Based Views are accepted by
view_to_iframe
as an argument.Calling
components.pyviews.pyapps.pyas_view()
is optional, but recommended.from reactpy import component, html\nfrom reactpy_django.components import view_to_iframe\n\nfrom . import views\n\nhello_world_iframe = view_to_iframe(views.HelloWorld.as_view())\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_iframe(),\n )\n
from django.http import HttpResponse\nfrom django.views import View\n\n\nclass HelloWorld(View):\n def get(self, request):\n return HttpResponse(\"Hello World!\")\n
How do I providefrom django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.HelloWorld)\n
args
andkwargs
to a converted view?This component accepts
*args
and**kwargs
arguments, which are sent to your provided view.All provided
components.pyviews.pyapps.py*args
and*kwargs
must be serializable values, since they are encoded into the URL.from reactpy import component, html\nfrom reactpy_django.components import view_to_iframe\n\nfrom . import views\n\nhello_world_iframe = view_to_iframe(\n views.hello_world,\n)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_iframe(\n \"value_1\",\n \"value_2\",\n kwarg1=\"abc\",\n kwarg2=\"123\",\n ),\n )\n
from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
How do I customize this component's behavior?from django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.hello_world)\n
This component accepts arguments that can be used to customize its behavior.
Below are all the arguments that can be used.
extra_props
This component accepts a
extra_props
parameter, which is a dictionary of additional properties to add to theiframe
element.For example, if you want to add a
components.pyviews.pyapps.pytitle
attribute to theiframe
element, you can do so like such:from reactpy import component, html\nfrom reactpy_django.components import view_to_iframe\n\nfrom . import views\n\nhello_world_iframe = view_to_iframe(\n views.hello_world, extra_props={\"title\": \"Hello World!\"}\n)\n\n\n@component\ndef my_component():\n return html.div(\n hello_world_iframe(),\n )\n
from django.http import HttpResponse\n\n\ndef hello_world(request):\n return HttpResponse(\"Hello World!\")\n
"},{"location":"reference/components/#django-css","title":"Django CSS","text":"from django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.hello_world)\n
Allows you to defer loading a CSS stylesheet until a component begins rendering. This stylesheet must be stored within Django's static files.
components.py
See Interfacefrom reactpy import component, html\nfrom reactpy_django.components import django_css\n\n\n@component\ndef my_component():\n return html.div(\n django_css(\"css/buttons.css\"),\n html.button(\"My Button!\"),\n )\n
Parameters
Name Type Description Defaultstatic_path
str
The path to the static file. This path is identical to what you would use on Django's{% static %}
template tag. N/Akey
Key | None
A key to uniquely identify this component which is unique amongst a component's immediate siblingsNone
Returns
Type DescriptionComponent
A ReactPy component. Can I load static CSS usinghtml.link
instead?While you can load stylesheets with
html.link
, keep in mind that loading this way does not ensure load order. Thus, your stylesheet will be loaded after your component is displayed. This would likely cause unintended visual behavior, so use this at your own discretion.Here's an example on what you should avoid doing for Django static files:
How do I load external CSS?from django.templatetags.static import static\nfrom reactpy import component, html\n\n\n@component\ndef my_component():\n return html.div(\n html.link({\"rel\": \"stylesheet\", \"href\": static(\"css/buttons.css\")}),\n html.button(\"My Button!\"),\n )\n
django_css
can only be used with local static files.For external CSS, you should use
html.link
.
Why not load my CSS infrom reactpy import component, html\n\n\n@component\ndef my_component():\n return html.div(\n html.link(\n {\"rel\": \"stylesheet\", \"href\": \"https://example.com/external-styles.css\"}\n ),\n html.button(\"My Button!\"),\n )\n
<head>
?Traditionally, stylesheets are loaded in your
<head>
using Django's{% static %}
template tag.However, to help improve webpage load times you can use this
"},{"location":"reference/components/#django-js","title":"Django JS","text":"django_css
component to defer loading your stylesheet until it is needed.Allows you to defer loading JavaScript until a component begins rendering. This JavaScript must be stored within Django's static files.
components.py
See Interfacefrom reactpy import component, html\nfrom reactpy_django.components import django_js\n\n\n@component\ndef my_component():\n return html.div(\n html.button(\"My Button!\"),\n django_js(\"js/scripts.js\"),\n )\n
Parameters
Name Type Description Defaultstatic_path
str
The path to the static file. This path is identical to what you would use on Django's{% static %}
template tag. N/Akey
Key | None
A key to uniquely identify this component which is unique amongst a component's immediate siblingsNone
Returns
Type DescriptionComponent
A ReactPy component. Can I load static JavaScript usinghtml.script
instead?While you can load JavaScript with
html.script
, keep in mind that loading this way does not ensure load order. Thus, your JavaScript will likely be loaded at an arbitrary time after your component is displayed.Here's an example on what you should avoid doing for Django static files:
How do I load external JS?from django.templatetags.static import static\nfrom reactpy import component, html\n\n\n@component\ndef my_component():\n return html.div(\n html.script({\"src\": static(\"js/scripts.js\")}),\n html.button(\"My Button!\"),\n )\n
django_js
can only be used with local static files.For external JavaScript, you should use
html.script
.
Why not load my JS infrom reactpy import component, html\n\n\n@component\ndef my_component():\n return html.div(\n html.script({\"src\": \"https://example.com/external-scripts.js\"}),\n html.button(\"My Button!\"),\n )\n
<head>
?Traditionally, JavaScript is loaded in your
<head>
using Django's{% static %}
template tag.However, to help improve webpage load times you can use this
"},{"location":"reference/decorators/","title":"Decorators","text":""},{"location":"reference/decorators/#overview","title":"Overview","text":"django_js
component to defer loading your JavaScript until it is needed.Decorator functions can be used within your
"},{"location":"reference/decorators/#user-passes-test","title":"User Passes Test","text":"components.py
to help simplify development.You can limit component access to users that pass a test function by using this decorator.
This decorator is inspired by Django's
components.pyuser_passes_test
decorator, but works with ReactPy components.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.decorators import user_passes_test\n\n\ndef is_authenticated(user):\n return user.is_authenticated\n\n\n@user_passes_test(is_authenticated)\n@component\ndef my_component():\n return html.div(\"I am logged in!\")\n
Parameters
Name Type Description Defaulttest_func
Callable[[AbstractUser], bool]
A function that accepts aUser
returns a boolean. N/Afallback
Any | None
The content to be rendered if the test fails. Typically is a ReactPy component or VDOM (reactpy.html
snippet).Returns
Type DescriptionComponentConstructor
A ReactPy component constructor. How do I render a different component if the test fails?You can use a component with the
components.pyfallback
argument, as seen below.
How do I render a simplefrom reactpy import component, html\nfrom reactpy_django.decorators import user_passes_test\n\n\n@component\ndef my_component_fallback():\n return html.div(\"I am NOT logged in!\")\n\n\ndef is_authenticated(user):\n return user.is_authenticated\n\n\n@user_passes_test(is_authenticated, fallback=my_component_fallback)\n@component\ndef my_component():\n return html.div(\"I am logged in!\")\n
reactpy.html
snippet if the test fails?You can use a
components.pyreactpy.html
snippet with thefallback
argument, as seen below.
"},{"location":"reference/hooks/","title":"Hooks","text":""},{"location":"reference/hooks/#overview","title":"Overview","text":"from reactpy import component, html\nfrom reactpy_django.decorators import user_passes_test\n\n\ndef is_authenticated(user):\n return user.is_authenticated\n\n\n@user_passes_test(is_authenticated, fallback=html.div(\"I am NOT logged in!\"))\n@component\ndef my_component():\n return html.div(\"I am logged in!\")\n
Prefabricated hooks can be used within your
components.py
to help simplify development.Note
Looking for standard React hooks?
This package only contains Django specific hooks. Standard hooks can be found within
"},{"location":"reference/hooks/#database-hooks","title":"Database Hooks","text":""},{"location":"reference/hooks/#use-query","title":"Use Query","text":"reactive-python/reactpy
.Execute functions in the background and return the result, typically to read data from the Django ORM.
The default postprocessor expects your query function to
return
a DjangoModel
orQuerySet
. This needs to be changed or disabled to execute other types of queries.Query functions can be sync or async.
components.pymodels.pyfrom channels.db import database_sync_to_async\nfrom example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_query\n\n\nasync def get_items():\n return await database_sync_to_async(TodoItem.objects.all)()\n\n\n@component\ndef todo_list():\n item_query = use_query(get_items)\n\n if item_query.loading:\n rendered_items = html.h2(\"Loading...\")\n elif item_query.error or not item_query.data:\n rendered_items = html.h2(\"Error when loading!\")\n else:\n rendered_items = html.ul(\n [html.li(item.text, key=item.pk) for item in item_query.data]\n )\n\n return html.div(\"Rendered items: \", rendered_items)\n
See Interfacefrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
Parameters
Name Type Description Defaultquery
Callable[FuncParams, Awaitable[Inferred]] | Callable[FuncParams, Inferred]
A function that executes a query and returns some data. N/Akwargs
dict[str, Any] | None
Keyword arguments to passed into thequery
function.None
thread_sensitive
bool
Whether to run your query function in thread sensitive mode. This mode only applies to sync query functions, and is turned on by default due to Django ORM limitations.True
postprocessor
AsyncPostprocessor | SyncPostprocessor | None
A callable that processes the querydata
before it is returned. The first argument of postprocessor function must be the querydata
. All proceeding arguments are optionalpostprocessor_kwargs
. This postprocessor function must return the modifieddata
.None
postprocessor_kwargs
dict[str, Any] | None
Keyworded arguments passed into thepostprocessor
function.None
Returns
Type DescriptionQuery[Inferred]
An object containingloading
/error
states, yourdata
(if the query has successfully executed), and arefetch
callable that can be used to re-run the query. How can I provide arguments to my query function?
components.pykwargs
can be provided to your query function via thekwargs=...
parameter.
How can I customize this hook's behavior?from reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef example_query(value: int, other_value: bool = False): ...\n\n\n@component\ndef my_component():\n query = use_query(example_query, {\"value\": 123, \"other_value\": True})\n\n return str(query.data)\n
This hook has several parameters that can be used to customize behavior.
Below are examples of values that can be modified.
thread_sensitive
Whether to run your synchronous query function in thread sensitive mode. Thread sensitive mode is turned on by default due to Django ORM limitations. See Django's
sync_to_async
docs docs for more information.This setting only applies to sync query functions, and will be ignored for async functions.
components.pyfrom reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef execute_thread_safe_operation():\n\"\"\"This is an example query function that does some thread-safe operation.\"\"\"\n pass\n\n\n@component\ndef my_component():\n query = use_query(execute_thread_safe_operation, thread_sensitive=False)\n\n if query.loading or query.error:\n return None\n\n return str(query.data)\n
postprocessor
By default, automatic recursive fetching of
ManyToMany
orForeignKey
fields is enabled within thedjango_query_postprocessor
. This is needed to preventSynchronousOnlyOperation
exceptions when accessing these fields within your ReactPy components.However, if you...
- Want to use this hook to defer IO intensive tasks to be computed in the background
- Want to to utilize
use_query
with a different ORM
... then you can either set a custom
components.pypostprocessor
, or disable all postprocessing behavior by modifying thepostprocessor=...
parameter. In the example below, we will set thepostprocessor
toNone
to disable postprocessing behavior.from reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef execute_io_intensive_operation():\n\"\"\"This is an example query function that does something IO intensive.\"\"\"\n pass\n\n\n@component\ndef my_component():\n query = use_query(\n execute_io_intensive_operation,\n postprocessor=None,\n )\n\n if query.loading or query.error:\n return None\n\n return str(query.data)\n
If you wish to create a custom
components.pypostprocessor
, you will need to create a function where the first must be the querydata
. All proceeding arguments are optionalpostprocessor_kwargs
(see below). Thispostprocessor
function must return the modifieddata
.from reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef my_postprocessor(data, example_kwarg=True):\n if example_kwarg:\n return data\n\n return dict(data)\n\n\ndef execute_io_intensive_operation():\n\"\"\"This is an example query function that does something IO intensive.\"\"\"\n pass\n\n\n@component\ndef my_component():\n query = use_query(\n execute_io_intensive_operation,\n postprocessor=my_postprocessor,\n postprocessor_kwargs={\"example_kwarg\": False},\n )\n\n if query.loading or query.error:\n return None\n\n return str(query.data)\n
postprocessor_kwargs
By default, automatic recursive fetching of
ManyToMany
orForeignKey
fields is enabled within thedjango_query_postprocessor
. This is needed to preventSynchronousOnlyOperation
exceptions when accessing these fields within your ReactPy components.However, if you have deep nested trees of relational data, this may not be a desirable behavior. In these scenarios, you may prefer to manually fetch these relational fields using a second
use_query
hook.You can disable the prefetching behavior of the default
components.pypostprocessor
(located atreactpy_django.utils.django_query_postprocessor
) via thepostprocessor_kwargs=...
parameter.from example.models import TodoItem\nfrom reactpy import component\nfrom reactpy_django.hooks import use_query\n\n\ndef get_model_with_relationships():\n\"\"\"This is an example query function that gets `MyModel` which has a ManyToMany field, and\n additionally other models that have formed a ForeignKey association to `MyModel`.\n\n ManyToMany Field: `many_to_many_field`\n ForeignKey Field: `foreign_key_field_set`\n \"\"\"\n return TodoItem.objects.get(id=1)\n\n\n@component\ndef my_component():\n query = use_query(\n get_model_with_relationships,\n postprocessor_kwargs={\"many_to_many\": False, \"many_to_one\": False},\n )\n\n if query.loading or query.error or not query.data:\n return None\n\n # By disabling `many_to_many` and `many_to_one`, accessing these fields will now\n # generate a `SynchronousOnlyOperation` exception\n return f\"{query.data.many_to_many_field} {query.data.foriegn_key_field_set}\"\n
Note: In Django's ORM design, the field name to access foreign keys is postfixed with
Can I make ORM calls without hooks?_set
by default.Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a
SynchronousOnlyOperation
exception.These
Can I make a failed query try again?SynchronousOnlyOperation
exceptions may be removed in a future version of Django. However, it is best practice to always perform IO operations (such as ORM queries) via hooks to prevent performance issues.Yes,
use_mutation
can be re-executed by callingreset()
on youruse_mutation
instance.For example, take a look at
components.pymodels.pyreset_event
below.from example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_mutation\n\n\ndef add_item(text: str):\n TodoItem(text=text).save()\n\n\n@component\ndef todo_list():\n item_mutation = use_mutation(add_item)\n\n def reset_event(event):\n item_mutation.reset()\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n if item_mutation.loading:\n mutation_status = html.h2(\"Adding...\")\n elif item_mutation.error:\n mutation_status = html.button({\"on_click\": reset_event}, \"Error: Try again!\")\n else:\n mutation_status = html.h2(\"Mutation done.\")\n\n return html.div(\n html.label(\"Add an item:\"),\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n )\n
Why does the example query function returnfrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
TodoItem.objects.all()
?This design decision was based on Apollo's
useQuery
hook, but ultimately helps avoid Django'sSynchronousOnlyOperation
exceptions.With the
"},{"location":"reference/hooks/#use-mutation","title":"Use Mutation","text":"Model
orQuerySet
your function returns, this hook uses the default postprocessor to ensure that all deferred or lazy fields are executed.Modify data in the background, typically to create/update/delete data from the Django ORM.
Mutation functions can
return False
to manually prevent yourrefetch=...
function from executing. All other returns are ignored.Mutation functions can be sync or async.
components.pymodels.pyfrom example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_mutation\n\n\nasync def add_item(text: str):\n await TodoItem(text=text).asave()\n\n\n@component\ndef todo_list():\n item_mutation = use_mutation(add_item)\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n if item_mutation.loading:\n mutation_status = html.h2(\"Adding...\")\n elif item_mutation.error:\n mutation_status = html.h2(\"Error when adding!\")\n else:\n mutation_status = html.h2(\"Mutation done.\")\n\n return html.div(\n html.label(\"Add an item:\"),\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n )\n
See Interfacefrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
Parameters
Name Type Description Defaultmutation
Callable[FuncParams, bool | None] | Callable[FuncParams, Awaitable[bool | None]]
A callable that performs Django ORM create, update, or delete functionality. If this function returnsFalse
, then yourrefetch
function will not be used. N/Athread_sensitive
bool
Whether to run the mutation in thread sensitive mode. This mode only applies to sync mutation functions, and is turned on by default due to Django ORM limitations.True
refetch
Callable[..., Any] | Sequence[Callable[..., Any]] | None
A query function (the function you provide to youruse_query
hook) or a sequence of query functions that need arefetch
if the mutation succeeds. This is useful for refreshing data after a mutation has been performed.None
Returns
Type DescriptionMutation[FuncParams]
An object containingloading
/error
states, and areset
callable that will setloading
/error
states to defaults. This object can be called to run the query. How can I provide arguments to my mutation function?
components.py*args
and**kwargs
can be provided to your mutation function viamutation(...)
parameters.
How can I customize this hook's behavior?from reactpy import component\nfrom reactpy_django.hooks import use_mutation\n\n\ndef example_mutation(value: int, other_value: bool = False):\n ...\n\n\n@component\ndef my_component():\n mutation = use_mutation(example_mutation)\n\n mutation(123, other_value=True)\n\n ...\n
This hook has several parameters that can be used to customize behavior.
Below are examples of values that can be modified.
thread_sensitive
Whether to run your synchronous mutation function in thread sensitive mode. Thread sensitive mode is turned on by default due to Django ORM limitations. See Django's
sync_to_async
docs docs for more information.This setting only applies to sync query functions, and will be ignored for async functions.
components.py
Can I make ORM calls without hooks?from reactpy import component, html\nfrom reactpy_django.hooks import use_mutation\n\n\ndef execute_thread_safe_mutation(text):\n\"\"\"This is an example mutation function that does some thread-safe operation.\"\"\"\n pass\n\n\n@component\ndef my_component():\n item_mutation = use_mutation(\n execute_thread_safe_mutation,\n thread_sensitive=False,\n )\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n if item_mutation.loading or item_mutation.error:\n mutation_status = html.h2(\"Doing something...\")\n elif item_mutation.error:\n mutation_status = html.h2(\"Error!\")\n else:\n mutation_status = html.h2(\"Done.\")\n\n return html.div(\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n )\n
Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a
SynchronousOnlyOperation
exception.These
Can I make a failed mutation try again?SynchronousOnlyOperation
exceptions may be removed in a future version of Django. However, it is best practice to always perform IO operations (such as ORM queries) via hooks to prevent performance issues.Yes,
use_mutation
can be re-executed by callingreset()
on youruse_mutation
instance.For example, take a look at
components.pymodels.pyreset_event
below.from example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_mutation\n\n\ndef add_item(text: str):\n TodoItem(text=text).save()\n\n\n@component\ndef todo_list():\n item_mutation = use_mutation(add_item)\n\n def reset_event(event):\n item_mutation.reset()\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n if item_mutation.loading:\n mutation_status = html.h2(\"Adding...\")\n elif item_mutation.error:\n mutation_status = html.button({\"on_click\": reset_event}, \"Error: Try again!\")\n else:\n mutation_status = html.h2(\"Mutation done.\")\n\n return html.div(\n html.label(\"Add an item:\"),\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n )\n
Canfrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
use_mutation
trigger a refetch ofuse_query
?Yes,
use_mutation
can queue a refetch of ause_query
via therefetch=...
argument.The example below is a merge of the
use_query
anduse_mutation
examples above with the addition of ause_mutation(refetch=...)
argument.Please note that
components.pymodels.pyrefetch
will cause alluse_query
hooks that useget_items
in the current component tree will be refetched.from example.models import TodoItem\nfrom reactpy import component, html\nfrom reactpy_django.hooks import use_mutation, use_query\n\n\ndef get_items():\n return TodoItem.objects.all()\n\n\ndef add_item(text: str):\n TodoItem(text=text).save()\n\n\n@component\ndef todo_list():\n item_query = use_query(get_items)\n item_mutation = use_mutation(add_item, refetch=get_items)\n\n def submit_event(event):\n if event[\"key\"] == \"Enter\":\n item_mutation(text=event[\"target\"][\"value\"])\n\n # Handle all possible query states\n if item_query.loading:\n rendered_items = html.h2(\"Loading...\")\n elif item_query.error or not item_query.data:\n rendered_items = html.h2(\"Error when loading!\")\n else:\n rendered_items = html.ul(\n html.li(item.text, key=item.pk) for item in item_query.data\n )\n\n # Handle all possible mutation states\n if item_mutation.loading:\n mutation_status = html.h2(\"Adding...\")\n elif item_mutation.error:\n mutation_status = html.h2(\"Error when adding!\")\n else:\n mutation_status = html.h2(\"Mutation done.\")\n\n return html.div(\n html.label(\"Add an item:\"),\n html.input({\"type\": \"text\", \"on_key_down\": submit_event}),\n mutation_status,\n rendered_items,\n )\n
"},{"location":"reference/hooks/#use-user-data","title":"Use User Data","text":"from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
Store or retrieve a
dict
containing user data specific to the connection'sUser
.This hook is useful for storing user-specific data, such as preferences, settings, or any generic key-value pairs.
User data saved with this hook is stored within the
components.pyREACTPY_DATABASE
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_user_data\n\n\n@component\ndef my_component():\n query, mutation = use_user_data()\n\n def on_submit(event):\n if event[\"key\"] == \"Enter\" and query.data:\n new_key = str(len(query.data))\n mutation({**query.data, new_key: event[\"target\"][\"value\"]})\n\n return html.div(\n html.div(f\"Data: {query.data}\"),\n html.div(f\"Loading: {query.loading | mutation.loading}\"),\n html.div(f\"Error(s): {query.error} {mutation.error}\"),\n html.input({\"on_key_press\": on_submit}),\n )\n
Parameters
Name Type Description Defaultdefault_data
None | dict[str, Callable[[], Any] | Callable[[], Awaitable[Any]] | Any]
A dictionary containing{key: default_value}
pairs. For computationally intensive defaults, yourdefault_value
can be sync or async functions that return the value to set.None
save_default_data
bool
IfTrue
,default_data
values will automatically be stored within the database if they do not exist.False
Returns
Type DescriptionUserData
ANamedTuple
containing aQuery
andMutation
objects used to access/modify user data. Read theuse_query
anduse_mutation
docs for more details. How do I set default values?You can configure default user data via the
default_data
parameter.This parameter accepts a dictionary containing a
components.py{key: default_value}
pairs. For computationally intensive defaults, yourdefault_value
can be sync or async functions that return the value to set.
"},{"location":"reference/hooks/#communication-hooks","title":"Communication Hooks","text":""},{"location":"reference/hooks/#use-channel-layer","title":"Use Channel Layer","text":"from reactpy import component, html\nfrom reactpy_django.hooks import use_user_data\n\n\n@component\ndef my_component():\n user_data = use_user_data(\n default_data={\n \"basic_example\": \"123\",\n \"computed_example_sync\": sync_default,\n \"computed_example_async\": async_default,\n }\n )\n\n return html.div(\n html.div(f\"Data: {user_data.query.data}\"),\n )\n\n\ndef sync_default():\n return ...\n\n\nasync def async_default():\n return ...\n
Subscribe to a Django Channels layer to send/receive messages.
Layers are a multiprocessing-safe communication system that allows you to send/receive messages between different parts of your application.
This is often used to create chat systems, synchronize data between components, or signal re-renders from outside your components.
components.py
See Interfacefrom reactpy import component, hooks, html\nfrom reactpy_django.hooks import use_channel_layer\n\n\n@component\ndef my_component():\n async def receive_message(message):\n set_message(message[\"text\"])\n\n async def send_message(event):\n if event[\"key\"] == \"Enter\":\n await sender({\"text\": event[\"target\"][\"value\"]})\n\n message, set_message = hooks.use_state(\"\")\n sender = use_channel_layer(\"my-channel-name\", receiver=receive_message)\n\n return html.div(\n f\"Received: {message}\",\n html.br(),\n \"Send: \",\n html.input({\"type\": \"text\", \"onKeyDown\": send_message}),\n )\n
Parameters
Name Type Description Defaultname
str | None
The name of the channel to subscribe to. If you define agroup_name
, you can keepname
undefined to auto-generate a unique name.None
group_name
str | None
If configured, any messages sent within this hook will be broadcasted to all channels in this group.None
group_add
bool
IfTrue
, the channel will automatically be added to the group when the component mounts.True
group_discard
bool
IfTrue
, the channel will automatically be removed from the group when the component dismounts.True
receiver
AsyncMessageReceiver | None
An async function that receives amessage: dict
from a channel. If more than one receiver waits on the same channel name, a random receiver will get the result.None
layer
str
The channel layer to use. This layer must be defined insettings.py:CHANNEL_LAYERS
.'default'
Returns
Type DescriptionAsyncMessageSender
An async callable that can send amessage: dict
. Extra Django configuration requiredIn order to use this hook, you will need to configure Django to enable channel layers.
The Django Channels documentation has information on what steps you need to take.
In summary, you will need to:
-
Install
redis
on your machine. -
Run the following command to install
channels-redis
in your Python environment.pip install channels-redis\n
-
Configure your
settings.py
to useRedisChannelLayer
as your layer backend.CHANNEL_LAYERS = {\n \"default\": {\n \"BACKEND\": \"channels_redis.core.RedisChannelLayer\",\n \"CONFIG\": {\n \"hosts\": [(\"127.0.0.1\", 6379)],\n },\n },\n}\n
If more than one receiver waits on the same channel, a random one will get the result.
To get around this, you can define a
group_name
to broadcast messages to all channels within a specific group. If you do not define a channelname
while using groups, ReactPy will automatically generate a unique channel name for you.In the example below, all messages sent by the
components.pysender
component will be received by allreceiver
components that exist (across every active client browser).
How do I signal a re-render from something that isn't a component?from reactpy import component, hooks, html\nfrom reactpy_django.hooks import use_channel_layer\n\n\n@component\ndef my_sender_component():\n sender = use_channel_layer(group_name=\"my-group-name\")\n\n async def submit_event(event):\n if event[\"key\"] == \"Enter\":\n await sender({\"text\": event[\"target\"][\"value\"]})\n\n return html.div(\n \"Message Sender: \",\n html.input({\"type\": \"text\", \"onKeyDown\": submit_event}),\n )\n\n\n@component\ndef my_receiver_component_1():\n message, set_message = hooks.use_state(\"\")\n\n async def receive_event(message):\n set_message(message[\"text\"])\n\n use_channel_layer(group_name=\"my-group-name\", receiver=receive_event)\n\n return html.div(f\"Message Receiver 1: {message}\")\n\n\n@component\ndef my_receiver_component_2():\n message, set_message = hooks.use_state(\"\")\n\n async def receive_event(message):\n set_message(message[\"text\"])\n\n use_channel_layer(group_name=\"my-group-name\", receiver=receive_event)\n\n return html.div(f\"Message Receiver 2: {message}\")\n
There are occasions where you may want to signal a re-render from something that isn't a component, such as a Django model signal.
In these cases, you can use the
use_channel_layer
hook to receive a signal within your component, and then use theget_channel_layer().send(...)
to send the signal.In the example below, the sender will send a signal every time
signals.pycomponents.pyExampleModel
is saved. Then, when the receiver component gets this signal, it explicitly callsset_message(...)
to trigger a re-render.from asgiref.sync import async_to_sync\nfrom channels.layers import get_channel_layer\nfrom django.db.models import Model\nfrom django.db.models.signals import pre_save\nfrom django.dispatch import receiver\n\n\nclass ExampleModel(Model): ...\n\n\n@receiver(pre_save, sender=ExampleModel)\ndef my_sender_signal(sender, instance, **kwargs):\n layer = get_channel_layer()\n\n # Example of sending a message to a channel\n async_to_sync(layer.send)(\"my-channel-name\", {\"text\": \"Hello World!\"})\n\n # Example of sending a message to a group channel\n async_to_sync(layer.group_send)(\"my-group-name\", {\"text\": \"Hello World!\"})\n
"},{"location":"reference/hooks/#connection-hooks","title":"Connection Hooks","text":""},{"location":"reference/hooks/#use-connection","title":"Use Connection","text":"from reactpy import component, hooks, html\nfrom reactpy_django.hooks import use_channel_layer\n\n\n@component\ndef my_receiver_component():\n message, set_message = hooks.use_state(\"\")\n\n async def receive_event(message):\n set_message(message[\"text\"])\n\n use_channel_layer(\"my-channel-name\", receiver=receive_event)\n\n return html.div(f\"Message Receiver: {message}\")\n
Returns the active connection, which is either a Django WebSocket or a HTTP Request.
components.py
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_connection\n\n\n@component\ndef my_component():\n connection = use_connection()\n\n return html.div(str(connection))\n
Parameters
None
Returns
Type DescriptionConnection
An object that contains acarrier
(WebSocket
orHttpRequest
),scope
, andlocation
."},{"location":"reference/hooks/#use-scope","title":"Use Scope","text":"Shortcut that returns the WebSocket or HTTP connection's scope.
components.py
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_scope\n\n\n@component\ndef my_component():\n scope = use_scope()\n\n return html.div(str(scope))\n
Parameters
None
Returns
Type DescriptionMutableMapping[str, Any]
The connection'sscope
."},{"location":"reference/hooks/#use-location","title":"Use Location","text":"Shortcut that returns the browser's current
components.pyLocation
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_location\n\n\n@component\ndef my_component():\n location = use_location()\n\n return html.div(location.pathname + location.search)\n
Parameters
None
Returns
Type DescriptionLocation
An object containing the current URL'spathname
andsearch
query."},{"location":"reference/hooks/#use-origin","title":"Use Origin","text":"Shortcut that returns the WebSocket or HTTP connection's
origin
.You can expect this hook to provide strings such as
components.pyhttp://example.com
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_origin\n\n\n@component\ndef my_component():\n origin = use_origin()\n\n return html.div(origin or \"No origin\")\n
Parameters
None
Returns
Type Descriptionstr | None
A string containing the browser's current origin, obtained from WebSocket or HTTP headers (if available)."},{"location":"reference/hooks/#use-root-id","title":"Use Root ID","text":"Shortcut that returns the root component's
id
from the WebSocket or HTTP connection.The root ID is currently a randomly generated
uuid4
(unique across all root component).This is useful when used in combination with
components.pyuse_channel_layer
to send messages to a specific component instance, and/or retain a backlog of messages in case that component is disconnected viause_channel_layer( ... , group_discard=False)
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_root_id\n\n\n@component\ndef my_component():\n root_id = use_root_id()\n\n return html.div(f\"Root ID: {root_id}\")\n
Parameters
None
Returns
Type Descriptionstr
A string containing the root component'sid
."},{"location":"reference/hooks/#use-user","title":"Use User","text":"Shortcut that returns the WebSocket or HTTP connection's
components.pyUser
.
See Interfacefrom reactpy import component, html\nfrom reactpy_django.hooks import use_user\n\n\n@component\ndef my_component():\n user = use_user()\n\n return html.div(user.username)\n
Parameters
None
Returns
Type DescriptionAbstractUser
A DjangoUser
, which can also be anAnonymousUser
."},{"location":"reference/html/","title":"HTML","text":""},{"location":"reference/html/#overview","title":"Overview","text":"We supply some pre-generated that HTML nodes can be used to help simplify development.
"},{"location":"reference/html/#pyscript","title":"PyScript","text":"Primitive HTML tag that is leveraged by
reactpy_django.components.pyscript_component
.This can be used as an alternative to the
reactpy.html.script
tag to execute JavaScript and run client-side Python code.Additionally, this tag functions identically to any other tag contained within
components.pymy_template.htmlreactpy.html
, and can be used in the same way.from reactpy import component, html\nfrom reactpy_django.html import pyscript\n\nexample_source_code = \"\"\"\nimport js\n\njs.console.log(\"Hello, World!\")\n\"\"\"\n\n\n@component\ndef server_side_component():\n return html.div(\n pyscript(example_source_code.strip()),\n )\n
You must call{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.server_side_component.py\" %}\n</body>\n\n</html>\n
pyscript_setup
in your Django template before using this tag!This requires using of the
my_template.html{% pyscript_setup %}
template tag to initialize PyScript on the client.
"},{"location":"reference/management-commands/","title":"Management Commands","text":""},{"location":"reference/management-commands/#overview","title":"Overview","text":"{% load reactpy %}\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
ReactPy exposes Django management commands that can be used to perform various ReactPy-related tasks.
"},{"location":"reference/management-commands/#clean-reactpy-command","title":"Clean ReactPy Command","text":"Command used to manually clean ReactPy data.
When using this command without arguments, it will perform all cleaning operations. You can limit cleaning to specific operations through arguments such as
--sessions
.Terminal
See Interfacepython manage.py clean_reactpy\n
Type
"},{"location":"reference/router/","title":"URL Router","text":""},{"location":"reference/router/#overview","title":"Overview","text":"python manage.py clean_reactpy --help
to see the available options.A Single Page Application URL router, which is a variant of
reactpy-router
that uses Django conventions.Note
Looking for more details on URL routing?
This package only contains Django specific URL routing features. Standard features can be found within
"},{"location":"reference/router/#django-router","title":"Django Router","text":"reactive-python/reactpy-router
.URL router that enables the ability to conditionally render other components based on the client's current URL
path
.Pitfall
All pages where
django_router
is used must have identical, or more permissive URL exposure within Django's URL patterns. You can think of the router component as a secondary, client-side router. Django still handles the primary server-side routes.We recommend creating a route with a wildcard
components.py.*
to forward routes to ReactPy. For example...re_path(r\"^/router/.*$\", my_reactpy_view)
See Interfacefrom reactpy import component, html\nfrom reactpy_django.router import django_router\nfrom reactpy_router import route\n\n\n@component\ndef my_component():\n return django_router(\n route(\"/router/\", html.div(\"Example 1\")),\n route(\"/router/any/<value>/\", html.div(\"Example 2\")),\n route(\"/router/integer/<int:value>/\", html.div(\"Example 3\")),\n route(\"/router/path/<path:value>/\", html.div(\"Example 4\")),\n route(\"/router/slug/<slug:value>/\", html.div(\"Example 5\")),\n route(\"/router/string/<str:value>/\", html.div(\"Example 6\")),\n route(\"/router/uuid/<uuid:value>/\", html.div(\"Example 7\")),\n route(\"/router/two_values/<int:value>/<str:value2>/\", html.div(\"Example 8\")),\n route(\"/router/*\", html.div(\"Fallback\")),\n )\n
Parameters
Name Type Description Default*routes
Route
An object fromreactpy-router
containing apath
,element
, and child*routes
. N/AReturns
Type DescriptionVdomDict | None
The matched component/path after it has been fully rendered. How is this different fromreactpy_router.simple.router
?This component utilizes
"},{"location":"reference/settings/","title":"Settings","text":""},{"location":"reference/settings/#overview","title":"Overview","text":"reactpy-router
under the hood, but provides a more Django-like URL routing syntax.These are ReactPy-Django's default settings values. You can modify these values in your Django project's
settings.py
to change the behavior of ReactPy.Note
The default configuration of ReactPy is suitable for the vast majority of use cases.
You should only consider changing settings when the necessity arises.
"},{"location":"reference/settings/#general-settings","title":"General Settings","text":""},{"location":"reference/settings/#reactpy_url_prefix","title":"REACTPY_URL_PREFIX
","text":"Default:
\"reactpy/\"
Example Value(s):
\"rp/\"
,\"render/reactpy/\"
The prefix used for all ReactPy WebSocket and HTTP URLs.
"},{"location":"reference/settings/#reactpy_default_query_postprocessor","title":"REACTPY_DEFAULT_QUERY_POSTPROCESSOR
","text":"Default:
\"reactpy_django.utils.django_query_postprocessor\"
Example Value(s):
\"example_project.postprocessor\"
,None
Dotted path to the default
reactpy_django.hooks.use_query
postprocessor function.Postprocessor functions can be async or sync. Here is an example of a sync postprocessor function:
def postprocessor(data):\n del data[\"foo\"]\n return data\n
Set
"},{"location":"reference/settings/#reactpy_auth_backend","title":"REACTPY_DEFAULT_QUERY_POSTPROCESSOR
toNone
to disable the default postprocessor.REACTPY_AUTH_BACKEND
","text":"Default:
\"django.contrib.auth.backends.ModelBackend\"
Example Value(s):
\"example_project.auth.MyModelBackend\"
Dotted path to the Django authentication backend to use for ReactPy components. This is only needed if:
- You are using
settings.py:REACTPY_AUTO_RELOGIN=True
and... - You are using
AuthMiddlewareStack
and... - You are using Django's
AUTHENTICATION_BACKENDS
setting and... - Your Django user model does not define a
backend
attribute.
REACTPY_AUTO_RELOGIN
","text":"Default:
False
Example Value(s):
True
Enabling this will cause component WebSocket connections to automatically re-login users that are already authenticated.
This is useful to continuously update
"},{"location":"reference/settings/#performance-settings","title":"Performance Settings","text":""},{"location":"reference/settings/#reactpy_database","title":"last_login
timestamps and refresh the Django login session.REACTPY_DATABASE
","text":"Default:
\"default\"
Example Value(s):
\"my-reactpy-database\"
Multiprocessing-safe database used by ReactPy for database-backed hooks and features.
If configuring this value, it is mandatory to enable our database router like such:
settings.py
"},{"location":"reference/settings/#reactpy_cache","title":"DATABASE_ROUTERS = [\"reactpy_django.database.Router\", ...]\n
REACTPY_CACHE
","text":"Default:
\"default\"
Example Value(s):
\"my-reactpy-cache\"
Cache used by ReactPy, typically for caching disk operations.
We recommend using
"},{"location":"reference/settings/#reactpy_backhaul_thread","title":"redis
,memcache
, orlocal-memory caching
.REACTPY_BACKHAUL_THREAD
","text":"Default:
False
Example Value(s):
True
Configures whether ReactPy components are rendered in a dedicated thread.
This allows the web server to process other traffic during ReactPy rendering. Vastly improves throughput with web servers such as
hypercorn
anduvicorn
.This setting is incompatible with
"},{"location":"reference/settings/#reactpy_default_hosts","title":"daphne
.REACTPY_DEFAULT_HOSTS
","text":"Default:
None
Example Value(s):
[\"localhost:8000\", \"localhost:8001\", \"localhost:8002/subdir\"]
The default host(s) that can render your ReactPy components.
ReactPy will use these hosts in a round-robin fashion, allowing for easy distributed computing. This is typically useful for self-hosted applications.
You can use the
"},{"location":"reference/settings/#reactpy_prerender","title":"host
argument in your template tag to manually override this default.REACTPY_PRERENDER
","text":"Default:
False
Example Value(s):
True
Configures whether to pre-render your components via HTTP, which enables SEO compatibility and reduces perceived latency.
During pre-rendering, there are some key differences in behavior:
- Only the component's first paint is pre-rendered.
- All
connection
hooks will provide HTTP variants. - The component will be non-interactive until a WebSocket connection is formed.
- The component is re-rendered once a WebSocket connection is formed.
You can use the
"},{"location":"reference/settings/#stability-settings","title":"Stability Settings","text":""},{"location":"reference/settings/#reactpy_reconnect_interval","title":"prerender
argument in your template tag to manually override this default.REACTPY_RECONNECT_INTERVAL
","text":"Default:
750
Example Value(s):
100
,2500
,6000
Milliseconds between client reconnection attempts.
"},{"location":"reference/settings/#reactpy_reconnect_backoff_multiplier","title":"REACTPY_RECONNECT_BACKOFF_MULTIPLIER
","text":"Default:
1.25
Example Value(s):
1
,1.5
,3
On each reconnection attempt, the
REACTPY_RECONNECT_INTERVAL
will be multiplied by this value to increase the time between attempts.You can keep time between each reconnection the same by setting this to
"},{"location":"reference/settings/#reactpy_reconnect_max_interval","title":"1
.REACTPY_RECONNECT_MAX_INTERVAL
","text":"Default:
60000
Example Value(s):
10000
,25000
,900000
Maximum milliseconds between client reconnection attempts.
This allows setting an upper bound on how high
"},{"location":"reference/settings/#reactpy_reconnect_max_retries","title":"REACTPY_RECONNECT_BACKOFF_MULTIPLIER
can increase the time between reconnection attempts.REACTPY_RECONNECT_MAX_RETRIES
","text":"Default:
150
Example Value(s):
0
,5
,300
Maximum number of reconnection attempts before the client gives up.
"},{"location":"reference/settings/#reactpy_session_max_age","title":"REACTPY_SESSION_MAX_AGE
","text":"Default:
259200
Example Value(s):
0
,60
,96000
Maximum seconds a ReactPy component session is valid for. Invalid sessions are deleted during ReactPy clean up.
ReactPy sessions include data such as
*args
and**kwargs
passed into your{% component %}
template tag.Use
"},{"location":"reference/settings/#auto-clean-settings","title":"Auto-Clean Settings","text":""},{"location":"reference/settings/#reactpy_clean_interval","title":"0
to not store any session data.REACTPY_CLEAN_INTERVAL
","text":"Default:
604800
Example Value(s):
0
,3600
,86400
,None
Minimum seconds between ReactPy automatic clean up operations.
After a component disconnection, the server will perform a clean up if this amount of time has passed since the last clean up.
Set this value to
"},{"location":"reference/settings/#reactpy_clean_sessions","title":"None
to disable automatic clean up operations.REACTPY_CLEAN_SESSIONS
","text":"Default:
True
Example Value(s):
False
Configures whether ReactPy should clean up expired component sessions during automatic clean up operations.
"},{"location":"reference/settings/#reactpy_clean_user_data","title":"REACTPY_CLEAN_USER_DATA
","text":"Default:
True
Example Value(s):
False
Configures whether ReactPy should clean up orphaned user data during automatic clean up operations.
Typically, user data does not become orphaned unless the server crashes during a
"},{"location":"reference/template-tag/","title":"Template Tag","text":""},{"location":"reference/template-tag/#overview","title":"Overview","text":"User
delete operation.Django template tags can be used within your HTML templates to provide ReactPy features.
"},{"location":"reference/template-tag/#component","title":"Component","text":"This template tag can be used to insert any number of ReactPy components onto your page.
Each component loaded via this template tag will receive a dedicated WebSocket connection to the server.
my_template.html
See Interface{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n </body>\n</html>\n
Parameters
Name Type Description Defaultdotted_path
str
The dotted path to the component to render. N/A*args
Any
The positional arguments to provide to the component. N/Aclass
str | None
The HTML class to apply to the top-level component div.None
key
Any
Force the component's root node to use a specific key value. Usingkey
within a template tag is effectively useless.None
host
str | None
The host to use for ReactPy connections. If unset, the host will be automatically configured.Example values include:localhost:8000
,example.com
,example.com/subdir
None
prerender
str
If\"true\"
the component will pre-rendered, which enables SEO compatibility and reduces perceived latency.\"false\"
offline
str
The dotted path to a component that will be displayed if your root component loses connection to the server. Keep in mind, thisoffline
component will be non-interactive (hooks won't operate).\"\"
**kwargs
Any
The keyword arguments to provide to the component. N/A Do not use context variables for the component pathThe ReactPy component finder requires that your component path is a string.
Do not use Django template/context variables for the component path. Failure to follow this warning will result in render failures.
For example, do not do the following:
my_template.htmlviews.py<!-- This is good -->\n{% component \"example_project.my_app.components.hello_world\" recipient=\"World\" %}\n\n<!-- This is bad -->\n{% component my_variable recipient=\"World\" %}\n
from django.shortcuts import render\n\n\ndef example_view(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_variable\": \"example_project.my_app.components.hello_world\"},\n )\n
Note: If you decide to not follow this warning, you will need to use the
Can I use multiple components on one page?register_component
function to manually register your components.You can add as many components to a webpage as needed by using the template tag multiple times. Retrofitting legacy sites to use ReactPy will typically involve many components on one page.
my_template.html{% load reactpy %}\n<!DOCTYPE html>\n<html>\n <body>\n <h1>{% component \"example_project.my_app.components.my_title\" %}</h1>\n <p>{% component \"example_project.my_app_2.components.goodbye_world\" class=\"bold small-font\" %}</p>\n{% component \"example_project.my_app_3.components.simple_button\" %}\n </body>\n</html>\n
Please note that components separated like this will not be able to interact with each other, except through database queries.
Additionally, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one component within your
Can I use positional arguments instead of keyword arguments?<body>
tag.You can use any combination of
my_template.htmlcomponents.py*args
/**kwargs
in your template tag.{% component \"example_project.my_app.components.frog_greeter\" 123 \"Mr. Froggles\" species=\"Grey Treefrog\" %}\n
Can I render components on a different server (distributed computing)?from reactpy import component\n\n\n@component\ndef frog_greeter(number, name, species=\"\"):\n return f\"Hello #{number}, {name} the {species}!\"\n
Yes! This is most commonly done through
my_template.htmlsettings.py:REACTPY_HOSTS
. However, you can use thehost
keyword to render components on a specific ASGI server....\n{% component \"example_project.my_app.components.do_something\" host=\"127.0.0.1:8001\" %}\n...\n
This configuration most commonly involves you deploying multiple instances of your project. But, you can also create dedicated Django project(s) that only render specific ReactPy components if you wish.
Here's a couple of things to keep in mind:
- If your host address are completely separate (
origin1.com != origin2.com
) you will need to configure CORS headers on your main application during deployment. - You will not need to register ReactPy WebSocket or HTTP paths on any applications that do not perform any component rendering.
- Your component will only be able to access your template tag's
*args
/**kwargs
if your applications share a common database.
This is most commonly done through
my_template.htmlsettings.py:REACTPY_PRERENDER
. However, you can use theprerender
keyword to pre-render a specific component.
How do I display something when the client disconnects?...\n{% component \"example_project.my_app.components.do_something\" prerender=\"true\" %}\n...\n
You can use the
my_template.htmloffline
keyword to display a specific component when the client disconnects from the server....\n{% component \"example_project.my_app.components.do_something\" offline=\"example_project.my_app.components.offline\" %}\n...\n
Note: The
"},{"location":"reference/template-tag/#pyscript-component","title":"PyScript Component","text":"offline
component will be non-interactive (hooks won't operate).This template tag can be used to insert any number of client-side ReactPy components onto your page.
By default, the only dependencies available are the Python standard library,
pyscript
,pyodide
,reactpy
core.Your PyScript component file requires a
def root()
component to function as the entry point.Pitfall
Your provided Python file is loaded directly into the client (web browser) as raw text, and ran using a PyScript interpreter. Be cautious about what you include in your Python file.
As a result of running client-side, Python packages within your local environment (such as those installed via
my_template.htmlhello_world.pypip install ...
) are not accessible within PyScript components.{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n\n<body>\n{% pyscript_component \"./example_project/my_app/components/hello_world.py\" %}\n</body>\n\n</html>\n
See Interfacefrom reactpy import component, html\n\n\n@component\ndef root():\n return html.div(\"Hello, World!\")\n
Parameters
Name Type Description Default*file_paths
str
File path to your client-side component. If multiple paths are provided, the contents are automatically merged. N/Ainitial
str | VdomDict | ComponentType
The initial HTML that is displayed prior to the PyScript component loads. This can either be a string containing raw HTML, areactpy.html
snippet, or a non-interactive component.\"\"
root
str
The name of the root component function.\"root\"
How do I execute JavaScript within PyScript components?PyScript components have the ability to directly execute standard library JavaScript using the
pyodide
js
module orpyscript
foreign function interface.The
root.pyjs
module has access to everything within the browser's JavaScript environment. Therefore, any global JavaScript functions loaded within your HTML<head>
can be called as well. However, be mindful of JavaScript load order!import js\nfrom reactpy import component, html\n\n\n@component\ndef root():\n\n def onClick(event):\n js.document.title = \"New window title\"\n\n return html.button({\"onClick\": onClick}, \"Click Me!\")\n
To import JavaScript modules in a fashion similar to
root.pymy_template.htmlimport {moment} from 'static/moment.js'
, you will need to configure your{% pyscript_setup %}
block to make the module available to PyScript. This module will be accessed withinpyscript.js_modules.*
. For more information, see the PyScript JS modules docs.from reactpy import component, html\n\n\n@component\ndef root():\n from pyscript.js_modules import moment\n\n return html.div(\n {\"id\": \"moment\"},\n \"Using the JavaScript package 'moment' to calculate time: \",\n moment.default().format(\"YYYY-MM-DD HH:mm:ss\"),\n )\n
Does my entire component need to be contained in one file?{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup extra_js='{\"/static/moment.js\":\"moment\"}' %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.root.py\" %}\n</body>\n\n</html>\n
Splitting a large file into multiple files is a common practice in software development.
However, PyScript components are run on the client browser. As such, they do not have access to your local development environment, and thus cannot
import
any local Python files.If your PyScript component file gets too large, you can declare multiple file paths instead. These files will automatically combined by ReactPy.
Here is how we recommend splitting your component into multiple files while avoiding local imports but retaining type hints.
my_template.htmlroot.pychild.py{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n\n<body>\n{% pyscript_component \"./example_project/my_app/components/root.py\"\n \"./example_project/my_app/components/child.py\" %}\n</body>\n\n</html>\n
from typing import TYPE_CHECKING\n\nfrom reactpy import component, html\n\nif TYPE_CHECKING:\n from .child import child_component\n\n\n@component\ndef root():\n return html.div(\"This text is from the root component.\", child_component())\n
How do I display something while the component is loading?from reactpy import component, html\n\n\n@component\ndef child_component():\n return html.div(\"This is a child component from a different file.\")\n
You can configure the
initial
keyword to display HTML while your PyScript component is loading.The value for
my_template.htmlinitial
is most commonly be a string containing raw HTML.<body>\n{% pyscript_component \"./example_project/my_app/components/root.py\" initial=\"<div> Loading ... </div>\" %}\n</body>\n
However, you can also insert a
my_template.htmlviews.pyreactpy.html
snippet or a non-interactive@component
via template context.<body>\n{% pyscript_component \"./example_project/my_app/components/root.py\" initial=my_initial_object %}\n</body>\n
Can I use a different name for my root component?from django.shortcuts import render\nfrom reactpy import html\n\n\ndef index(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_initial_object\": html.div(\"Loading ...\")},\n )\n
Yes, you can use the
my_template.htmlmain.pyroot
keyword to specify a different name for your root function.<body>\n{% pyscript_component \"./example_project/my_app/components/main.py\" root=\"main\" %}\n</body>\n
"},{"location":"reference/template-tag/#pyscript-setup","title":"PyScript Setup","text":"from reactpy import component, html\n\n\n@component\ndef main():\n return html.div(\"Hello, World!\")\n
This template tag configures the current page to be able to run
pyscript
.You can optionally use this tag to configure the current PyScript environment. For example, you can include a list of Python packages to automatically install within the PyScript environment.
my_template.html
See Interface{% load reactpy %}\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
Parameters
Name Type Description Default*extra_py
str
Dependencies that need to be loaded on the page for your PyScript components. Each dependency must be contained within it's own string and written in Python requirements file syntax. N/Aextra_js
str | dict
A JSON string or Python dictionary containing a vanilla JavaScript module URL and thename: str
to access it withinpyscript.js_modules.*
.\"\"
config
str | dict
A JSON string or Python dictionary containing PyScript configuration values.\"\"
How do I install additional Python dependencies?Dependencies must be available on
pypi
and declared in your{% pyscript_setup %}
block using Python requirements file syntax.These dependencies are automatically downloaded and installed into the PyScript client-side environment when the page is loaded.
my_template.html
How do I install additional Javascript dependencies?<head>\n <title>ReactPy</title>\n{% pyscript_setup \"dill==0.3.5\" \"markdown<=3.6.0\" \"nest_asyncio\" \"titlecase\" %}\n</head>\n
You can use the
my_template.htmlviews.pyextra_js
keyword to load additional JavaScript modules into your PyScript environment.{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup extra_js=my_extra_js_object %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.root.py\" %}\n</body>\n\n</html>\n
from django.shortcuts import render\nfrom django.templatetags.static import static\n\n\ndef index(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_extra_js_object\": {static(\"moment.js\"): \"moment\"}},\n )\n
The value for
my_template.htmlextra_js
is most commonly a Python dictionary, but JSON strings are also supported.
How do I modify the{% load reactpy %}\n<!DOCTYPE html>\n<html>\n\n<head>\n <title>ReactPy</title>\n{% pyscript_setup extra_js='{\"/static/moment.js\":\"moment\"}' %}\n</head>\n\n<body>\n{% component \"example_project.my_app.components.root.py\" %}\n</body>\n\n</html>\n
pyscript
default configuration?You can modify the default PyScript configuration by providing a value to the
my_template.htmlconfig
keyword.<head>\n <title>ReactPy</title>\n{% pyscript_setup config='{\"experimental_create_proxy\":\"auto\"}' %}\n</head>\n
While this value is most commonly a JSON string, Python dictionary objects are also supported.
my_template.htmlviews.py<head>\n <title>ReactPy</title>\n{% pyscript_setup config=my_config_object %}\n</head>\n
"},{"location":"reference/utils/","title":"Utilities","text":""},{"location":"reference/utils/#overview","title":"Overview","text":"from django.shortcuts import render\n\n\ndef index(request):\n return render(\n request,\n \"my_template.html\",\n context={\"my_config_object\": {\"experimental_create_proxy\": \"auto\"}},\n )\n
Utility functions provide various miscellaneous functionality for advanced use cases.
Pitfall
Any utility functions not documented here are not considered part of the public API and may change without notice.
"},{"location":"reference/utils/#register-iframe","title":"Register Iframe","text":"This function is used register a view as an
iframe
with ReactPy.It is mandatory to use this function alongside
apps.pyview_to_iframe
.
See Interfacefrom django.apps import AppConfig\nfrom reactpy_django.utils import register_iframe\n\nfrom . import views\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_iframe(views.hello_world)\n
Parameters
Name Type Description Defaultview
Callable | View | str
The view to register. Can be a function or class based view, or a dotted path to a view. N/AReturns
Only use this withinNone
MyAppConfig.ready()
You should always call
"},{"location":"reference/utils/#register-component","title":"Register Component","text":"register_iframe
within a DjangoMyAppConfig.ready()
method. This ensures you will retain multiprocessing compatibility, such as with ASGI web server workers.This function is used register a root component with ReactPy.
Typically, this function is automatically called on all components contained within Django templates.
apps.py
See Interfacefrom django.apps import AppConfig\nfrom reactpy_django.utils import register_component\n\n\nclass ExampleAppConfig(AppConfig):\n name = \"example\"\n\n def ready(self):\n register_component(\"example_project.my_app.components.hello_world\")\n
Parameters
Name Type Description Defaultcomponent
ComponentConstructor | str
The component to register. Can be a component function or dotted path to a component. N/AReturns
Only use this withinNone
MyAppConfig.ready()
You should always call
Do I need to use this?register_component
within a DjangoMyAppConfig.ready()
method. This ensures you will retain multiprocessing compatibility, such as with ASGI web server workers.You typically will not need to use this function.
For security reasons, ReactPy requires all root components to be registered. However, all components contained within Django templates are automatically registered.
This function is commonly needed when you have configured your
"},{"location":"reference/utils/#django-query-postprocessor","title":"Django Query Postprocessor","text":"host
to a dedicated Django rendering application that doesn't have templates.This is the default postprocessor for the
use_query
hook.Since ReactPy is rendered within an
components.pymodels.pyasyncio
loop, this postprocessor is exists to prevent Django'sSynchronousOnlyException
by recursively prefetching fields within aModel
orQuerySet
. This prefetching step works to eliminate Django's lazy execution behavior.from example.models import TodoItem\nfrom reactpy import component\nfrom reactpy_django.hooks import use_query\nfrom reactpy_django.utils import django_query_postprocessor\n\n\ndef get_items():\n return TodoItem.objects.all()\n\n\n@component\ndef todo_list():\n # These postprocessor options are functionally equivalent to ReactPy-Django's default values\n item_query = use_query(\n get_items,\n postprocessor=django_query_postprocessor,\n postprocessor_kwargs={\"many_to_many\": True, \"many_to_one\": True},\n )\n\n return item_query.data\n
See Interfacefrom django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n text: CharField = CharField(max_length=255)\n
Parameters
Name Type Description Defaultdata
QuerySet | Model
TheModel
orQuerySet
to recursively fetch fields from. N/Amany_to_many
bool
Whether or not to recursively fetchManyToManyField
relationships.True
many_to_one
bool
Whether or not to recursively fetchForeignKey
relationships.True
Returns
Type DescriptionQuerySet | Model
TheModel
orQuerySet
with all fields fetched."}]} \ No newline at end of file - Client-side Python components can now be rendered via the new