diff --git a/develop/about/changelog/index.html b/develop/about/changelog/index.html index 061475f4..a55b3208 100644 --- a/develop/about/changelog/index.html +++ b/develop/about/changelog/index.html @@ -2,7 +2,7 @@ If you see this page, you probably meant to visit the other CHANGELOG.md (all caps). --->

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.


Unreleased

Changed

Removed

4.0.0 - 2024-06-22

Added

Changed

Removed

Fixed

3.8.1 - 2024-05-07

Added

3.8.0 - 2024-02-20

Added

Changed

3.7.0 - 2024-01-30

Added

3.6.0 - 2024-01-10

Added

Changed

Deprecated

Fixed

3.5.1 - 2023-09-07

Added

Changed

3.5.0 - 2023-08-26

Added

Changed

Django 4.2+ is required

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.

Removed

3.4.0 - 2023-08-18

Added

Changed

Deprecated

Removed

3.3.2 - 2023-08-13

Added

Fixed

3.3.1 - 2023-08-08

Added

Changed

3.3.0 - 2023-08-05

Added

Changed

3.2.1 - 2023-06-29

Added

Fixed

3.2.0 - 2023-06-08

Added

Changed

3.1.0 - 2023-05-06

Added

Changed

Fixed

3.0.1 - 2023-04-06

Changed

3.0.0-reactpy - 2023-03-30

Changed

3.0.0 - 2023-03-08

Note

This is Django-IDOM's biggest update yet!

To upgrade from previous version you will need to...

  1. Install django-idom >= 3.0.0
  2. Run idom rewrite-keys <DIR> and idom rewrite-camel-case-props <DIR> to update your idom.html.* calls to the new syntax
  3. Run python manage.py migrate to create the new Django-IDOM database entries

Added

Changed

Removed

Fixed

Security

2.2.1 - 2023-01-09

Fixed

2.2.0 - 2022-12-28

Added

Changed

Removed

2.1.0 - 2022-11-01

Changed

Fixed

Security

2.0.1 - 2022-10-18

Fixed

2.0.0 - 2022-10-17

Added

Changed

Fixed

1.2.0 - 2022-09-19

Added

Changed

Fixed

1.1.0 - 2022-07-01

Added

Changed

1.0.0 - 2022-05-22

Added

Changed

Removed

0.0.5 - 2022-04-04

Changed

Fixed

0.0.4 - 2022-03-05

Changed

0.0.3 - 2022-02-19

Changed

0.0.2 - 2022-01-30

Added

Changed

Removed

Fixed

Security

0.0.1 - 2021-08-18

Added


Last update: February 1, 2024
Authors: Mark Bakhit
\ No newline at end of file diff --git a/develop/about/code/index.html b/develop/about/code/index.html index 13c50b38..280601ef 100644 --- a/develop/about/code/index.html +++ b/develop/about/code/index.html @@ -7,4 +7,4 @@ python manage.py test

Running Django test web server

If you want to manually run the Django test application, you can use the following command:

cd tests
 python manage.py runserver
-

Creating a pull request

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.


Last update: January 29, 2024
Authors: Mark Bakhit
\ No newline at end of file +

Creating a pull request

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.


Last update: January 29, 2024
Authors: Mark Bakhit
\ No newline at end of file diff --git a/develop/about/docs/index.html b/develop/about/docs/index.html index e32f93ef..99542117 100644 --- a/develop/about/docs/index.html +++ b/develop/about/docs/index.html @@ -3,4 +3,4 @@

Then, by running the command below you can:

pip install -r requirements.txt --upgrade
 

Finally, to verify that everything is working properly, you can manually run the docs preview web server.

cd docs
 mkdocs serve
-

Navigate to http://127.0.0.1:8000 to view a preview of the documentation.

GitHub Pull Request

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.


Last update: January 29, 2024
Authors: Mark Bakhit
\ No newline at end of file +

Navigate to http://127.0.0.1:8000 to view a preview of the documentation.

GitHub Pull Request

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.


Last update: January 29, 2024
Authors: Mark Bakhit
\ No newline at end of file diff --git a/develop/learn/add-reactpy-to-a-django-project/index.html b/develop/learn/add-reactpy-to-a-django-project/index.html index 173114c5..223c12c6 100644 --- a/develop/learn/add-reactpy-to-a-django-project/index.html +++ b/develop/learn/add-reactpy-to-a-django-project/index.html @@ -71,7 +71,7 @@ )
Where is my asgi.py?

If you do not have an asgi.py, follow the channels installation guide.

Step 5: Run database migrations

Run Django's migrate command to initialize ReactPy-Django's database table.

python manage.py migrate
 

Step 6: Check your configuration

Run Django's check command to verify if ReactPy was set up correctly.

python manage.py check
-

Step 7: Create your first component

The next page 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 simple hello_world component.

1
+

Step 7: Create your first component

The next page 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 simple hello_world component.

1
 2
 3
 4
@@ -80,7 +80,7 @@
 @component
 def hello_world(recipient: str):
     return html.h1(f"Hello {recipient}!")
-

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 and kwargs into your component function. After reading the code below, pay attention to how the function definition for hello_world (from the previous example) accepts a recipient argument.

1
+

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 and kwargs into your component function. After reading the code below, pay attention to how the function definition for hello_world (from the previous example) accepts a recipient argument.

1
 2
 3
 4
@@ -93,4 +93,4 @@
     {% component "example_project.my_app.components.hello_world" recipient="World" %}
   </body>
 </html>
-

Last update: October 22, 2024
Authors: Mark Bakhit
\ No newline at end of file +

Last update: October 22, 2024
Authors: Mark Bakhit
\ No newline at end of file diff --git a/develop/learn/your-first-component/index.html b/develop/learn/your-first-component/index.html index c230d37e..fbb3e22a 100644 --- a/develop/learn/your-first-component/index.html +++ b/develop/learn/your-first-component/index.html @@ -1,4 +1,4 @@ - Your First Component - ReactPy-Django
Skip to content

Your First Component

Overview

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.


Selecting a Django App

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:

  1. You have a Django app named my_app, which was created by Django's startapp command.
  2. You have placed my_app directly into your Django project folder (./example_project/my_app). This is common for small projects.
How do I organize my Django project for ReactPy?

ReactPy-Django has no project structure requirements. Organize everything as you wish, just like any Django project.

Defining a component

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 will define your component function(s) using the @component decorator.

1
+ Your First Component - ReactPy-Django       

Your First Component

Overview

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.


Selecting a Django App

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:

  1. You have a Django app named my_app, which was created by Django's startapp command.
  2. You have placed my_app directly into your Django project folder (./example_project/my_app). This is common for small projects.
How do I organize my Django project for ReactPy?

ReactPy-Django has no project structure requirements. Organize everything as you wish, just like any Django project.

Defining a component

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 will define your component function(s) using the @component decorator.

1
 2
 3
 4
@@ -7,7 +7,7 @@
 @component
 def hello_world(recipient: str):
     return html.h1(f"Hello {recipient}!")
-
What should I name my ReactPy files and functions?

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 as components/navbar.py.

Ultimately, components are referenced by Python dotted path in my_template.html (see next step). This dotted path must be valid to Python's importlib.

What does the decorator actually do?

While not all components need to be decorated, there are a few features this decorator adds to your components.

  1. 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).
  2. The ability to use hooks.
    • The decorator is required on any component where hooks are defined.
  3. Scoped failures.
    • If a decorated component generates an exception, then only that one component will fail to render.

Embedding in a template

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 and kwargs into your component function. After reading the code below, pay attention to how the function definition for hello_world (from the previous step) accepts a recipient argument.

1
+
What should I name my ReactPy files and functions?

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 as components/navbar.py.

Ultimately, components are referenced by Python dotted path in my_template.html (see next step). This dotted path must be valid to Python's importlib.

What does the decorator actually do?

While not all components need to be decorated, there are a few features this decorator adds to your components.

  1. 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).
  2. The ability to use hooks.
    • The decorator is required on any component where hooks are defined.
  3. Scoped failures.
    • If a decorated component generates an exception, then only that one component will fail to render.

Embedding in a template

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 and kwargs into your component function. After reading the code below, pay attention to how the function definition for hello_world (from the previous step) accepts a recipient argument.

1
 2
 3
 4
@@ -20,7 +20,7 @@
     {% component "example_project.my_app.components.hello_world" recipient="World" %}
   </body>
 </html>
-
Components are automatically registered!

ReactPy-Django will automatically register any component that is referenced in a Django HTML template. This means you typically do not need to manually register components in your Django app.

Please note that this HTML template must be properly stored within a registered Django app. ReactPy-Django will output a console log message containing all detected components when the server starts up.

Do not use context variables for the component path

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:

1
+
Components are automatically registered!

ReactPy-Django will automatically register any component that is referenced in a Django HTML template. This means you typically do not need to manually register components in your Django app.

Please note that this HTML template must be properly stored within a registered Django app. ReactPy-Django will output a console log message containing all detected components when the server starts up.

Do not use context variables for the component path

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:

1
 2
 3
 4
@@ -46,7 +46,7 @@
         "my_template.html",
         context={"my_variable": "example_project.my_app.components.hello_world"},
     )
-

Note: If you decide to not follow this warning, you will need to use the register_component function to manually register your components.

Can I use multiple components on one page?

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.

1
+

Note: If you decide to not follow this warning, you will need to use the register_component function to manually register your components.

Can I use multiple components on one page?

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.

1
 2
 3
 4
@@ -63,7 +63,7 @@
         {% component "example_project.my_app_3.components.my_button" %}
     </body>
 </html>
-

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 <body> tag.

Where is my templates folder?

If you do not have a ./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 to settings.py:INSTALLED_APPS.

Setting up a Django view

Within your Django app's views.py file, you will need to create a view function to render the HTML template my_template.html (from the previous step).

1
+

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 <body> tag.

Where is my templates folder?

If you do not have a ./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 to settings.py:INSTALLED_APPS.

Setting up a Django view

Within your Django app's views.py file, you will need to create a view function to render the HTML template my_template.html (from the previous step).

1
 2
 3
 4
diff --git a/develop/reference/components/index.html b/develop/reference/components/index.html
index 36ff0470..c6bca932 100644
--- a/develop/reference/components/index.html
+++ b/develop/reference/components/index.html
@@ -1,4 +1,4 @@
- Components - ReactPy-Django       

Components

Overview

We supply some pre-designed that components can be used to help simplify development.


PyScript Component

This allows you to embedded any number of client-side PyScript components within traditional ReactPy components.

By default, the only available dependencies are the Python standard library, pyscript, pyodide, reactpy core.

The entire file path provided is loaded directly into the browser, and must have a def root() component to act as the entry point.

Pitfall

Similar to JavaScript, your provided Python file is loaded directly into the client (web browser) as raw text to run using the PyScript interpreter. Be cautious about what you include in your Python file.

As a result being client-sided, Python packages within your local environment (such as those installed via pip install ...) are not accessible within PyScript components.

 1
+ Components - ReactPy-Django       

Components

Overview

We supply some pre-designed that components can be used to help simplify development.


PyScript Component

This allows you to embedded any number of client-side PyScript components within traditional ReactPy components.

By default, the only available dependencies are the Python standard library, pyscript, pyodide, reactpy core.

The entire file path provided is loaded directly into the browser, and must have a def root() component to act as the entry point.

Pitfall

Similar to JavaScript, your provided Python file is loaded directly into the client (web browser) as raw text to run using the PyScript interpreter. Be cautious about what you include in your Python file.

As a result being client-sided, Python packages within your local environment (such as those installed via pip install ...) are not accessible within PyScript components.

 1
  2
  3
  4
@@ -66,7 +66,7 @@
     <title>ReactPy</title>
     {% pyscript_setup %}
 </head>
-
How do I execute JavaScript within PyScript components?

PyScript components several options available to execute JavaScript, including...

Pyodide JS Module

The Pyodide js 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, you will need to be mindful of JavaScript load order if using async or deferred loading!

 1
+
How do I execute JavaScript within PyScript components?

PyScript components several options available to execute JavaScript, including...

Pyodide JS Module

The Pyodide js 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, you will need to be mindful of JavaScript load order if using async or deferred loading!

 1
  2
  3
  4
@@ -137,7 +137,7 @@
 </body>
 
 </html>
-
Does my entire component need to be contained in one file?

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.

 1
+
Does my entire component need to be contained in one file?

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.

 1
  2
  3
  4
diff --git a/develop/reference/hooks/index.html b/develop/reference/hooks/index.html
index 38eb26ae..69c09eef 100644
--- a/develop/reference/hooks/index.html
+++ b/develop/reference/hooks/index.html
@@ -110,7 +110,7 @@
         return None
 
     return str(query.data)
-

postprocessor

By default, automatic recursive fetching of ManyToMany or ForeignKey fields is enabled within the django_query_postprocessor. This is needed to prevent SynchronousOnlyOperation exceptions when accessing these fields within your ReactPy components.

However, if you...

  1. Want to use this hook to defer IO intensive tasks to be computed in the background
  2. Want to to utilize use_query with a different ORM

... then you can either set a custom postprocessor, or disable all postprocessing behavior by modifying the postprocessor=... parameter. In the example below, we will set the postprocessor to None to disable postprocessing behavior.

 1
+

postprocessor

By default, automatic recursive fetching of ManyToMany or ForeignKey fields is enabled within the django_query_postprocessor. This is needed to prevent SynchronousOnlyOperation exceptions when accessing these fields within your ReactPy components.

However, if you...

  1. Want to use this hook to defer IO intensive tasks to be computed in the background
  2. Want to to utilize use_query with a different ORM

... then you can either set a custom postprocessor, or disable all postprocessing behavior by modifying the postprocessor=... parameter. In the example below, we will set the postprocessor to None to disable postprocessing behavior.

 1
  2
  3
  4
@@ -204,7 +204,7 @@
         return None
 
     return str(query.data)
-

postprocessor_kwargs

By default, automatic recursive fetching of ManyToMany or ForeignKey fields is enabled within the django_query_postprocessor. This is needed to prevent SynchronousOnlyOperation 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 postprocessor (located at reactpy_django.utils.django_query_postprocessor) via the postprocessor_kwargs=... parameter.

 1
+

postprocessor_kwargs

By default, automatic recursive fetching of ManyToMany or ForeignKey fields is enabled within the django_query_postprocessor. This is needed to prevent SynchronousOnlyOperation 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 postprocessor (located at reactpy_django.utils.django_query_postprocessor) via the postprocessor_kwargs=... parameter.

 1
  2
  3
  4
@@ -259,7 +259,7 @@
     # By disabling `many_to_many` and `many_to_one`, accessing these fields will now
     # generate a `SynchronousOnlyOperation` exception
     return f"{query.data.many_to_many_field} {query.data.foriegn_key_field_set}"
-

Note: In Django's ORM design, the field name to access foreign keys is postfixed with _set by default.

Can I make ORM calls without hooks?

Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a SynchronousOnlyOperation exception.

These 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.

Can I make a failed query try again?

Yes, use_mutation can be re-executed by calling reset() on your use_mutation instance.

For example, take a look at reset_event below.

 1
+

Note: In Django's ORM design, the field name to access foreign keys is postfixed with _set by default.

Can I make ORM calls without hooks?

Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a SynchronousOnlyOperation exception.

These 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.

Can I make a failed query try again?

Yes, use_mutation can be re-executed by calling reset() on your use_mutation instance.

For example, take a look at reset_event below.

 1
  2
  3
  4
@@ -487,7 +487,7 @@
         html.input({"type": "text", "on_key_down": submit_event}),
         mutation_status,
     )
-
Can I make ORM calls without hooks?

Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a SynchronousOnlyOperation exception.

These 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.

Can I make a failed mutation try again?

Yes, use_mutation can be re-executed by calling reset() on your use_mutation instance.

For example, take a look at reset_event below.

 1
+
Can I make ORM calls without hooks?

Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a SynchronousOnlyOperation exception.

These 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.

Can I make a failed mutation try again?

Yes, use_mutation can be re-executed by calling reset() on your use_mutation instance.

For example, take a look at reset_event below.

 1
  2
  3
  4
diff --git a/develop/reference/html/index.html b/develop/reference/html/index.html
index fa79f9a0..dc3c75cb 100644
--- a/develop/reference/html/index.html
+++ b/develop/reference/html/index.html
@@ -54,7 +54,7 @@
 </body>
 
 </html>
-
You must call pyscript_setup in your Django template before using this tag!

This requires using of the {% pyscript_setup %} template tag to initialize PyScript on the client.

1
+
You must call pyscript_setup in your Django template before using this tag!

This requires using of the {% pyscript_setup %} template tag to initialize PyScript on the client.

1
 2
 3
 4
@@ -65,4 +65,4 @@
     <title>ReactPy</title>
     {% pyscript_setup %}
 </head>
-

Last update: October 22, 2024
Authors: Mark Bakhit
\ No newline at end of file +

Last update: October 22, 2024
Authors: Mark Bakhit
\ No newline at end of file diff --git a/develop/reference/template-tag/index.html b/develop/reference/template-tag/index.html index 3b19e966..413e361e 100644 --- a/develop/reference/template-tag/index.html +++ b/develop/reference/template-tag/index.html @@ -1,4 +1,4 @@ - Template Tag - ReactPy-Django

Template Tag

Overview

Django template tags can be used within your HTML templates to provide ReactPy features.


Component

This template tag can be used to insert any number of server-side ReactPy components onto your page.

Each component loaded via this template tag will receive a dedicated WebSocket connection to the server.

1
+ Template Tag - ReactPy-Django       

Template Tag

Overview

Django template tags can be used within your HTML templates to provide ReactPy features.


Component

This template tag can be used to insert any number of server-side ReactPy components onto your page.

Each component loaded via this template tag will receive a dedicated WebSocket connection to the server.

1
 2
 3
 4
@@ -11,7 +11,7 @@
     {% component "example_project.my_app.components.hello_world" recipient="World" %}
   </body>
 </html>
-
See Interface

Parameters

Name Type Description Default
dotted_path str The dotted path to the component to render. N/A
*args Any The positional arguments to provide to the component. N/A
class 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. Using key 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, this offline 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 path

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:

1
+
See Interface

Parameters

Name Type Description Default
dotted_path str The dotted path to the component to render. N/A
*args Any The positional arguments to provide to the component. N/A
class 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. Using key 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, this offline 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 path

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:

1
 2
 3
 4
diff --git a/develop/search/search_index.json b/develop/search/search_index.json
index 42e02f42..5b679458 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/#changed","title":"Changed","text":"
  • Now using ReactPy-Router v1 for URL routing, which comes with a slightly different API than before.
  • Removed dependency on aiofile.
"},{"location":"about/changelog/#removed","title":"Removed","text":"
  • Removed the following deprecated features:
    • The compatibility argument on reactpy_django.components.view_to_component
    • reactpy_django.components.view_to_component usage as a decorator
    • reactpy_django.decorators.auth_required
    • reactpy_django.REACTPY_WEBSOCKET_PATH
    • settings.py:REACTPY_WEBSOCKET_URL
"},{"location":"about/changelog/#400-2024-06-22","title":"4.0.0 - 2024-06-22","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
  • 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.
"},{"location":"about/changelog/#changed_1","title":"Changed","text":"
  • New syntax for use_query and use_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
"},{"location":"about/changelog/#removed_1","title":"Removed","text":"
  • QueryOptions and MutationOptions have been removed. The value contained within these objects are now passed directly into the hook.
"},{"location":"about/changelog/#fixed","title":"Fixed","text":"
  • Resolved a bug where Django-ReactPy would not properly detect settings.py:DEBUG.
"},{"location":"about/changelog/#381-2024-05-07","title":"3.8.1 - 2024-05-07","text":""},{"location":"about/changelog/#added_1","title":"Added","text":"
  • Python 3.12 compatibility
"},{"location":"about/changelog/#380-2024-02-20","title":"3.8.0 - 2024-02-20","text":""},{"location":"about/changelog/#added_2","title":"Added","text":"
  • Built-in cross-process communication mechanism via the reactpy_django.hooks.use_channel_layer hook.
  • Access to the root component's id via the reactpy_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.
"},{"location":"about/changelog/#changed_2","title":"Changed","text":"
  • Simplified code for cascading deletion of user data.
"},{"location":"about/changelog/#370-2024-01-30","title":"3.7.0 - 2024-01-30","text":""},{"location":"about/changelog/#added_3","title":"Added","text":"
  • An \"offline component\" can now be displayed when the client disconnects from the server.
  • URL router now supports a * wildcard to create default routes.
"},{"location":"about/changelog/#360-2024-01-10","title":"3.6.0 - 2024-01-10","text":""},{"location":"about/changelog/#added_4","title":"Added","text":"
  • 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 to True 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 views view_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 update last_login timestamps and refresh the Django login session.
"},{"location":"about/changelog/#changed_3","title":"Changed","text":"
  • Renamed undocumented utility function ComponentPreloader to RootComponentFinder.
  • It is now recommended to call as_view() when using view_to_component or view_to_iframe with Class Based Views.
  • For thread safety, thread_sensitive=True has been enabled in all sync_to_async functions where ORM queries are possible.
  • reactpy_django.hooks.use_mutation now has a __call__ method. So rather than writing my_mutation.execute(...), you can now write my_mutation(...).
"},{"location":"about/changelog/#deprecated","title":"Deprecated","text":"
  • The compatibility argument on reactpy_django.components.view_to_component is deprecated.
    • Use view_to_iframe as a replacement.
  • 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.
  • 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).
"},{"location":"about/changelog/#fixed_1","title":"Fixed","text":"
  • Fixed a bug where exception stacks would not print on failed component renders.
"},{"location":"about/changelog/#351-2023-09-07","title":"3.5.1 - 2023-09-07","text":""},{"location":"about/changelog/#added_5","title":"Added","text":"
  • Warning W018 (Suspicious position of 'reactpy_django' in INSTALLED_APPS) has been added.
"},{"location":"about/changelog/#changed_4","title":"Changed","text":"
  • The default postprocessor can now disabled by setting REACTPY_DEFAULT_QUERY_POSTPROCESSOR to None.
  • Massive overhaul of docs styling.
"},{"location":"about/changelog/#350-2023-08-26","title":"3.5.0 - 2023-08-26","text":""},{"location":"about/changelog/#added_6","title":"Added","text":"
  • 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!
"},{"location":"about/changelog/#changed_5","title":"Changed","text":"
  • 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 if settings.py:DEBUG is enabled.
  • Bumped the minimum @reactpy/client version to 0.3.1
  • Use TypeScript instead of JavaScript for this repository.
  • Bumped the minimum Django version to 4.2.
Django 4.2+ is required

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_2","title":"Removed","text":"
  • settings.py:REACTPY_RECONNECT_MAX is removed. See the docs for the new REACTPY_RECONNECT_* settings.
"},{"location":"about/changelog/#340-2023-08-18","title":"3.4.0 - 2023-08-18","text":""},{"location":"about/changelog/#added_7","title":"Added","text":"
  • 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 the component 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.
"},{"location":"about/changelog/#changed_6","title":"Changed","text":"
  • 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.
"},{"location":"about/changelog/#deprecated_1","title":"Deprecated","text":"
  • reactpy_django.REACTPY_WEBSOCKET_PATH is deprecated. The identical replacement is REACTPY_WEBSOCKET_ROUTE.
  • settings.py:REACTPY_WEBSOCKET_URL is deprecated. The similar replacement is REACTPY_URL_PREFIX.
"},{"location":"about/changelog/#removed_3","title":"Removed","text":"
  • 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 of channels do not require installation via INSTALLED_APPS to receive an ASGI web server.
"},{"location":"about/changelog/#332-2023-08-13","title":"3.3.2 - 2023-08-13","text":""},{"location":"about/changelog/#added_8","title":"Added","text":"
  • ReactPy WebSocket will now decode messages via orjson resulting in an ~6% overall performance improvement.
  • Built-in asyncio event loops are now patched via nest_asyncio, resulting in an ~10% overall performance improvement. This has no performance impact if you are running your web server with uvloop.
"},{"location":"about/changelog/#fixed_2","title":"Fixed","text":"
  • 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 by uvicorn when REACTPY_BACKHAUL_THREAD = True.
  • Fixed bug on Windows where rendering behavior would be jittery with daphne when REACTPY_BACKHAUL_THREAD = True.
"},{"location":"about/changelog/#331-2023-08-08","title":"3.3.1 - 2023-08-08","text":""},{"location":"about/changelog/#added_9","title":"Added","text":"
  • Additional system checks for ReactPy misconfigurations.
"},{"location":"about/changelog/#changed_7","title":"Changed","text":"
  • REACTPY_BACKHAUL_THREAD now defaults to False.
"},{"location":"about/changelog/#330-2023-08-05","title":"3.3.0 - 2023-08-05","text":""},{"location":"about/changelog/#added_10","title":"Added","text":"
  • Added system checks for a variety of common ReactPy misconfigurations.
  • REACTPY_BACKHAUL_THREAD setting to enable/disable threading behavior.
"},{"location":"about/changelog/#changed_8","title":"Changed","text":"
  • If using settings.py:REACTPY_DATABASE, reactpy_django.database.Router must now be registered in settings.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.
"},{"location":"about/changelog/#321-2023-06-29","title":"3.2.1 - 2023-06-29","text":""},{"location":"about/changelog/#added_11","title":"Added","text":"
  • Template tag exception details are now rendered on the webpage when settings.py:DEBUG is enabled.
"},{"location":"about/changelog/#fixed_3","title":"Fixed","text":"
  • Prevent exceptions within the component template tag from causing the whole template to fail to render.
"},{"location":"about/changelog/#320-2023-06-08","title":"3.2.0 - 2023-06-08","text":""},{"location":"about/changelog/#added_12","title":"Added","text":"
  • 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.
"},{"location":"about/changelog/#changed_9","title":"Changed","text":"
  • Using SessionMiddlewareStack is now optional.
  • Using AuthMiddlewareStack is now optional.
"},{"location":"about/changelog/#310-2023-05-06","title":"3.1.0 - 2023-05-06","text":""},{"location":"about/changelog/#added_13","title":"Added","text":"
  • 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 accepts reactpy_django.types.MutationOptions option to customize how mutations are executed.
"},{"location":"about/changelog/#changed_10","title":"Changed","text":"
  • The mutate argument on reactpy_django.hooks.use_mutation has been renamed to mutation.
"},{"location":"about/changelog/#fixed_4","title":"Fixed","text":"
  • Fix bug where ReactPy utilizes Django's default cache timeout, which can prematurely expire the component cache.
"},{"location":"about/changelog/#301-2023-04-06","title":"3.0.1 - 2023-04-06","text":""},{"location":"about/changelog/#changed_11","title":"Changed","text":"
  • reactpy-django database entries are no longer cleaned during Django application startup. Instead, it will occur on webpage loads if REACTPY_RECONNECT_MAX seconds has elapsed since the last cleaning.
"},{"location":"about/changelog/#300-reactpy-2023-03-30","title":"3.0.0-reactpy - 2023-03-30","text":""},{"location":"about/changelog/#changed_12","title":"Changed","text":"
  • django-idom has been renamed to reactpy-django! Please note that all references to the word idom in your code should be changed to reactpy. See the docs for more details.
"},{"location":"about/changelog/#300-2023-03-08","title":"3.0.0 - 2023-03-08","text":"Note

This is Django-IDOM's biggest update yet!

To upgrade from previous version you will need to...

  1. Install django-idom >= 3.0.0
  2. Run idom rewrite-keys <DIR> and idom rewrite-camel-case-props <DIR> to update your idom.html.* calls to the new syntax
  3. Run python manage.py migrate to create the new Django-IDOM database entries
"},{"location":"about/changelog/#added_14","title":"Added","text":"
  • The idom client will automatically configure itself to debug mode depending on settings.py:DEBUG.
  • use_connection hook for returning the browser's active Connection.
  • IDOM_CACHE is now configurable within settings.py to whatever cache name you wish.
"},{"location":"about/changelog/#changed_13","title":"Changed","text":"
  • 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 example className now becomes class_name.
    • key=... is now declared within the props dict (rather than as a kwarg).
  • 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 to IDOM_RECONNECT_MAX.
"},{"location":"about/changelog/#removed_4","title":"Removed","text":"
  • django_idom.hooks.use_websocket has been removed. The similar replacement is django_idom.hooks.use_connection.
  • django_idom.types.IdomWebsocket has been removed. The similar replacement is django_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 the IDOM_CACHE setting.
"},{"location":"about/changelog/#fixed_5","title":"Fixed","text":"
  • view_to_component will now retain the contents of a <head> tag when rendering.
  • React client is now set to production rather than development.
  • use_query will now utilize field.related_name when postprocessing many-to-one relationships.
"},{"location":"about/changelog/#security","title":"Security","text":"
  • 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.
"},{"location":"about/changelog/#221-2023-01-09","title":"2.2.1 - 2023-01-09","text":""},{"location":"about/changelog/#fixed_6","title":"Fixed","text":"
  • 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.
"},{"location":"about/changelog/#220-2022-12-28","title":"2.2.0 - 2022-12-28","text":""},{"location":"about/changelog/#added_15","title":"Added","text":"
  • Add options: QueryOptions parameter to use_query to allow for configuration of this hook.
"},{"location":"about/changelog/#changed_14","title":"Changed","text":"
  • By default, use_query will recursively prefetch all many-to-many or many-to-one relationships to prevent SynchronousOnlyOperation exceptions.
"},{"location":"about/changelog/#removed_5","title":"Removed","text":"
  • django_idom.hooks._fetch_lazy_fields has been deleted. The equivalent replacement is django_idom.utils.django_query_postprocessor.
"},{"location":"about/changelog/#210-2022-11-01","title":"2.1.0 - 2022-11-01","text":""},{"location":"about/changelog/#changed_15","title":"Changed","text":"
  • Minimum channels version is now 4.0.0.
"},{"location":"about/changelog/#fixed_7","title":"Fixed","text":"
  • Change type hint on view_to_component callable to have request 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))
"},{"location":"about/changelog/#security_1","title":"Security","text":"
  • Add note to docs about potential information exposure via view_to_component when using compatibility=True.
"},{"location":"about/changelog/#201-2022-10-18","title":"2.0.1 - 2022-10-18","text":""},{"location":"about/changelog/#fixed_8","title":"Fixed","text":"
  • Ability to use key=... parameter on all prefabricated components.
"},{"location":"about/changelog/#200-2022-10-17","title":"2.0.0 - 2022-10-17","text":""},{"location":"about/changelog/#added_16","title":"Added","text":"
  • use_origin hook for returning the browser's location.origin.
"},{"location":"about/changelog/#changed_16","title":"Changed","text":"
  • view_to_component now returns a Callable, instead of directly returning a Component. Check the docs for new usage info.
  • use_mutation and use_query will now log any query failures.
"},{"location":"about/changelog/#fixed_9","title":"Fixed","text":"
  • Allow use_mutation to have refetch=None, as the docs suggest is possible.
  • use_query will now prefetch all fields to prevent SynchronousOnlyOperation exceptions.
  • view_to_component, django_css, and django_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
"},{"location":"about/changelog/#120-2022-09-19","title":"1.2.0 - 2022-09-19","text":""},{"location":"about/changelog/#added_17","title":"Added","text":"
  • 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.
"},{"location":"about/changelog/#changed_17","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.40.2
  • Testing suite now uses playwright instead of selenium
"},{"location":"about/changelog/#fixed_10","title":"Fixed","text":"
  • IDOM preloader is no longer sensitive to whitespace within template tags.
"},{"location":"about/changelog/#110-2022-07-01","title":"1.1.0 - 2022-07-01","text":""},{"location":"about/changelog/#added_18","title":"Added","text":"
  • django_css and django_js components to defer loading CSS & JS files until needed.
"},{"location":"about/changelog/#changed_18","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.39.0
"},{"location":"about/changelog/#100-2022-05-22","title":"1.0.0 - 2022-05-22","text":""},{"location":"about/changelog/#added_19","title":"Added","text":"
  • Django specific hooks! use_websocket, use_scope, and use_location are now available within the django_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.
"},{"location":"about/changelog/#changed_19","title":"Changed","text":"
  • idom_component template tag has been renamed to component
  • Bumped the minimum IDOM version to 0.38.0
"},{"location":"about/changelog/#removed_6","title":"Removed","text":"
  • websocket parameter for components has been removed. Functionally, it is replaced with django_idom.hooks.use_websocket.
"},{"location":"about/changelog/#005-2022-04-04","title":"0.0.5 - 2022-04-04","text":""},{"location":"about/changelog/#changed_20","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.37.2
"},{"location":"about/changelog/#fixed_11","title":"Fixed","text":"
  • ModuleNotFoundError: No module named idom.core.proto caused by IDOM 0.37.2
"},{"location":"about/changelog/#004-2022-03-05","title":"0.0.4 - 2022-03-05","text":""},{"location":"about/changelog/#changed_21","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.37.1
"},{"location":"about/changelog/#003-2022-02-19","title":"0.0.3 - 2022-02-19","text":""},{"location":"about/changelog/#changed_22","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.36.3
"},{"location":"about/changelog/#002-2022-01-30","title":"0.0.2 - 2022-01-30","text":""},{"location":"about/changelog/#added_20","title":"Added","text":"
  • Ability to declare the HTML class of the top-level component div
  • name = ... parameter to IDOM HTTP paths for use with django.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
"},{"location":"about/changelog/#changed_23","title":"Changed","text":"
  • 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
"},{"location":"about/changelog/#removed_7","title":"Removed","text":"
  • IDOM_WEB_MODULES_PATH has been replaced with Django include(...)
  • IDOM_WS_MAX_RECONNECT_DELAY has been renamed to IDOM_WS_MAX_RECONNECT_TIMEOUT
  • idom_web_modules cache back-end has been renamed to idom
"},{"location":"about/changelog/#fixed_12","title":"Fixed","text":"
  • Increase test timeout values to prevent false positives
  • Windows compatibility for building Django-IDOM
"},{"location":"about/changelog/#security_2","title":"Security","text":"
  • Fixed potential directory traversal attack on the IDOM web modules URL
"},{"location":"about/changelog/#001-2021-08-18","title":"0.0.1 - 2021-08-18","text":""},{"location":"about/changelog/#added_21","title":"Added","text":"
  • Support for IDOM within the Django
"},{"location":"about/code/","title":"Code","text":""},{"location":"about/code/#overview","title":"Overview","text":"

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 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.

"},{"location":"about/code/#creating-an-environment","title":"Creating an environment","text":"

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:

  1. When pip install is run on the reactpy-django package.
  2. Every time python manage.py ... or nox ... is run
"},{"location":"about/code/#running-the-full-test-suite","title":"Running the full test suite","text":"

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:

nox -t test -- --headless\n
"},{"location":"about/code/#running-django-tests","title":"Running Django tests","text":"

If you want to only run our Django tests in your current environment, you can use the following command:

cd tests\npython manage.py test\n
"},{"location":"about/code/#running-django-test-web-server","title":"Running Django test web server","text":"

If you want to manually run the Django test application, you can use the following command:

cd tests\npython manage.py runserver\n
"},{"location":"about/code/#creating-a-pull-request","title":"Creating a pull request","text":"

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 http://127.0.0.1:8000 to view a preview of the documentation.

"},{"location":"about/docs/#github-pull-request","title":"GitHub Pull Request","text":"

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.

pip install reactpy-django\n
"},{"location":"learn/add-reactpy-to-a-django-project/#step-2-configure-settingspy","title":"Step 2: Configure settings.py","text":"

Add \"reactpy_django\" to INSTALLED_APPS in your settings.py file.

settings.py
INSTALLED_APPS = [\n    ...,\n    \"reactpy_django\",\n]\n
Enable ASGI and Django Channels (Required)

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 and channels installation docs:

  1. Install channels[daphne]
  2. Add \"daphne\" to INSTALLED_APPS.

    INSTALLED_APPS = [\n    \"daphne\",\n    ...,\n]\n
  3. Set your ASGI_APPLICATION variable.

    ASGI_APPLICATION = \"example_project.asgi.application\"\n
Configure ReactPy settings (Optional)

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: Configure urls.py","text":"

Add ReactPy HTTP paths to your urlpatterns in your urls.py file.

urls.py
from django.urls import include, path\n\nurlpatterns = [\n    ...,\n    path(\"reactpy/\", include(\"reactpy_django.http.urls\")),\n]\n
"},{"location":"learn/add-reactpy-to-a-django-project/#step-4-configure-asgipy","title":"Step 4: Configure asgi.py","text":"

Register ReactPy's WebSocket using REACTPY_WEBSOCKET_ROUTE in your asgi.py file.

asgi.py
import 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
Add AuthMiddlewareStack (Optional)

There are many situations where you need to access the Django User or Session objects within ReactPy components. For example, if you want to:

  1. Access the User that is currently logged in
  2. Access Django's Session object
  3. Login or logout the current User

In these situations will need to ensure you are using AuthMiddlewareStack.

from 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
Where is my asgi.py?

If you do not have an asgi.py, follow the channels installation guide.

"},{"location":"learn/add-reactpy-to-a-django-project/#step-5-run-database-migrations","title":"Step 5: Run database migrations","text":"

Run Django's migrate command to initialize ReactPy-Django's database table.

python manage.py migrate\n
"},{"location":"learn/add-reactpy-to-a-django-project/#step-6-check-your-configuration","title":"Step 6: Check your configuration","text":"

Run Django's check command to verify if ReactPy was set up correctly.

python manage.py check\n
"},{"location":"learn/add-reactpy-to-a-django-project/#step-7-create-your-first-component","title":"Step 7: Create your first component","text":"

The next page 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 simple hello_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 and kwargs into your component function. After reading the code below, pay attention to how the function definition for hello_world (from the previous example) accepts a recipient argument.

{% 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
"},{"location":"learn/your-first-component/","title":"Your First Component","text":""},{"location":"learn/your-first-component/#overview","title":"Overview","text":"

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:

  1. You have a Django app named my_app, which was created by Django's startapp command.
  2. You have placed my_app directly into your Django project folder (./example_project/my_app). This is common for small projects.
How do I organize my Django project for ReactPy?

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 will define your component function(s) using the @component decorator.

components.py
from reactpy import component, html\n\n@component\ndef hello_world(recipient: str):\n    return html.h1(f\"Hello {recipient}!\")\n
What should I name my ReactPy files and functions?

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 as components/navbar.py.

Ultimately, components are referenced by Python dotted path in my_template.html (see next step). This dotted path must be valid to Python's importlib.

What does the decorator actually do?

While not all components need to be decorated, there are a few features this decorator adds to your components.

  1. 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).
  2. The ability to use hooks.
    • The decorator is required on any component where hooks are defined.
  3. Scoped failures.
    • If a decorated component generates an exception, then only that one component will fail to render.
"},{"location":"learn/your-first-component/#embedding-in-a-template","title":"Embedding in a template","text":"

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 and kwargs into your component function. After reading the code below, pay attention to how the function definition for hello_world (from the previous step) accepts a recipient argument.

my_template.html
{% 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 automatically registered!

ReactPy-Django will automatically register any component that is referenced in a Django HTML template. This means you typically do not need to manually register components in your Django app.

Please note that this HTML template must be properly stored within a registered Django app. ReactPy-Django will output a console log message containing all detected components when the server starts up.

Do not use context variables for the component path

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 register_component function to manually register your components.

Can I use multiple components on one page?

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.my_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 <body> tag.

Where is my templates folder?

If you do not have a ./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 to settings.py:INSTALLED_APPS.

"},{"location":"learn/your-first-component/#setting-up-a-django-view","title":"Setting up a Django view","text":"

Within your Django app's views.py file, you will need to create a view function to render the HTML template my_template.html (from the previous step).

views.py
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.py and define what URL it should be accessible at.

urls.py
from django.urls import path\nfrom example import views\n\nurlpatterns = [\n    path(\"example/\", views.index),\n]\n
Which urls.py do I add my views to?

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 urls.py you will use Django's include function to link it all together.

"},{"location":"learn/your-first-component/#viewing-your-component","title":"Viewing your component","text":"

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 use manage.py runserver for production

This 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 available dependencies are the Python standard library, pyscript, pyodide, reactpy core.

The entire file path provided is loaded directly into the browser, and must have a def root() component to act as the entry point.

Pitfall

Similar to JavaScript, your provided Python file is loaded directly into the client (web browser) as raw text to run using the PyScript interpreter. Be cautious about what you include in your Python file.

As a result being client-sided, Python packages within your local environment (such as those installed via pip install ...) are not accessible within PyScript components.

components.pyroot.pymy_template.html
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
{% 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
See Interface

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/A initial str | VdomDict | ComponentType The initial HTML that is displayed prior to the PyScript component loads. This can either be a string containing raw HTML, a reactpy.html snippet, or a non-interactive component. \"\" root str The name of the root component function. \"root\" You must call pyscript_setup in your Django template before using this tag!

This requires using of the {% pyscript_setup %} template tag to initialize PyScript on the client.

my_template.html
{% load reactpy %}\n\n<head>\n    <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
How do I execute JavaScript within PyScript components?

PyScript components several options available to execute JavaScript, including...

  • Pyodide's js module
  • Pyscript's foreign function interface
  • Pyscript's JavaScript modules.

Pyodide JS Module

The Pyodide js 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, you will need to be mindful of JavaScript load order if using async or deferred loading!

root.py
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

PyScript FFI

...

PyScript JS Modules

Assuming you have a local bundle stored within your project's static files, you can import JavaScript modules in a fashion similar to import {moment} from 'static/moment.js'. You will first need to configure your {% pyscript_setup %} block to make the moment.js module available to PyScript. Then, this module can be accessed within pyscript.js_modules.*.

root.pymy_template.html
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
{% 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
Does my entire component need to be contained in one file?

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.py
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            \"./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
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
How do I display something while the component is loading?

You can configure the initial keyword to display HTML while your PyScript component is loading.

The value for initial is most commonly be a reactpy.html snippet or a non-interactive @component.

components.py
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
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
Can I use a different name for my root component?

Yes, you can use the root keyword to specify a different name for your root function.

components.pymain.py
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
from reactpy import component, html\n\n\n@component\ndef main():\n    return html.div(\"Hello, World!\")\n
"},{"location":"reference/components/#view-to-component","title":"View To Component","text":"

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.py
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
See Interface

Parameters

Name Type Description Default view Callable | View | str The view to convert, or the view's dotted path as a string. N/A transforms 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 If True, an exception will be generated if the HTML does not perfectly adhere to HTML5. True

Returns

Type Description constructor A function that takes request, *args, key, **kwargs and returns a ReactPy component. Note that *args and **kwargs are directly provided to your view. Existing limitations

There 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.
How do I use this for Class Based Views?

Class Based Views are accepted by view_to_component as an argument.

Calling as_view() is optional, but recommended.

components.pyviews.py
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
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 provide request, args, and kwargs to a converted view?

This component accepts request, *args, and **kwargs arguments, which are sent to your provided view.

components.pyviews.py
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
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
How do I customize this component's behavior?

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 strict_parsing parameter to False. This uses libxml2 recovery algorithm, which is designed to be similar to how web browsers would attempt to parse non-standard or broken HTML.

components.pyviews.py
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 your transforms 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 id, you can create a transform like such:

components.pyviews.py
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
from django.http import HttpResponse\n\n\ndef hello_world(request):\n    return HttpResponse('<div id=\"hello-world\"> Hello World! </div>')\n
"},{"location":"reference/components/#view-to-iframe","title":"View To Iframe","text":"

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 than view_to_component, it comes with different limitations.

Compatible with sync or async Function Based Views and Class Based Views.

components.pyviews.pyapps.py
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.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
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
See Interface

Parameters

Name Type Description Default view Callable | View | str The view function or class to convert. N/A extra_props Mapping[str, Any] | None Additional properties to add to the iframe element. None

Returns

Type Description constructor A function that takes *args, key, **kwargs and returns a ReactPy component. Note that *args and **kwargs are directly provided to your view. Existing limitations

There 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.
How do I use this for Class Based Views?

Class Based Views are accepted by view_to_iframe as an argument.

Calling as_view() is optional, but recommended.

components.pyviews.pyapps.py
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
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.HelloWorld)\n
How do I provide args and kwargs to a converted view?

This component accepts *args and **kwargs arguments, which are sent to your provided view.

All provided *args and *kwargs must be serializable values, since they are encoded into the URL.

components.pyviews.pyapps.py
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
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
How do I customize this component's behavior?

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 the iframe element.

For example, if you want to add a title attribute to the iframe element, you can do so like such:

components.pyviews.pyapps.py
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
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
"},{"location":"reference/components/#django-css","title":"Django CSS","text":"

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
from 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
See Interface

Parameters

Name Type Description Default static_path str The path to the static file. This path is identical to what you would use on Django's {% static %} template tag. N/A key Key | None A key to uniquely identify this component which is unique amongst a component's immediate siblings None

Returns

Type Description Component A ReactPy component. Can I load static CSS using html.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:

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
How do I load external CSS?

django_css can only be used with local static files.

For external CSS, you should use html.link.

from 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
Why not load my CSS in <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 django_css component to defer loading your stylesheet until it is needed.

"},{"location":"reference/components/#django-js","title":"Django JS","text":"

Allows you to defer loading JavaScript until a component begins rendering. This JavaScript must be stored within Django's static files.

components.py
from 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
See Interface

Parameters

Name Type Description Default static_path str The path to the static file. This path is identical to what you would use on Django's {% static %} template tag. N/A key Key | None A key to uniquely identify this component which is unique amongst a component's immediate siblings None

Returns

Type Description Component A ReactPy component. Can I load static JavaScript using html.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:

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
How do I load external JS?

django_js can only be used with local static files.

For external JavaScript, you should use html.script.

from 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
Why not load my JS in <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 django_js component to defer loading your JavaScript until it is needed.

"},{"location":"reference/decorators/","title":"Decorators","text":""},{"location":"reference/decorators/#overview","title":"Overview","text":"

Decorator functions can be used within your components.py to help simplify development.

"},{"location":"reference/decorators/#user-passes-test","title":"User Passes Test","text":"

You can limit component access to users that pass a test function by using this decorator.

This only works with ReactPy components, and is inspired by Django's user_passes_test decorator.

components.py
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)\n@component\ndef my_component():\n    return html.div(\"I am logged in!\")\n
See Interface

Parameters

Name Type Description Default test_func Callable[[AbstractUser], bool] A function that accepts a User returns a boolean. N/A fallback Any | None The content to be rendered if the test fails. Typically is a ReactPy component or VDOM (reactpy.html snippet).

Returns

Type Description ComponentConstructor A ReactPy component constructor. How do I render a different component if the test fails?

You can use a component with the fallback argument, as seen below.

components.py
from 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
How do I render a simple reactpy.html snippet if the test fails?

You can use a reactpy.html snippet with the fallback argument, as seen below.

components.py
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
"},{"location":"reference/hooks/","title":"Hooks","text":""},{"location":"reference/hooks/#overview","title":"Overview","text":"

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 reactive-python/reactpy.

"},{"location":"reference/hooks/#database-hooks","title":"Database Hooks","text":""},{"location":"reference/hooks/#use-query","title":"Use Query","text":"

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 Django Model or QuerySet. This needs to be changed or disabled to execute other types of queries.

Query functions can be sync or async.

components.pymodels.py
from 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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
See Interface

Parameters

Name Type Description Default query Callable[FuncParams, Awaitable[Inferred]] | Callable[FuncParams, Inferred] A function that executes a query and returns some data. N/A kwargs dict[str, Any] | None Keyword arguments to passed into the query 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 query data before it is returned. The first argument of postprocessor function must be the query data. All proceeding arguments are optional postprocessor_kwargs. This postprocessor function must return the modified data. None postprocessor_kwargs dict[str, Any] | None Keyworded arguments passed into the postprocessor function. None

Returns

Type Description Query[Inferred] An object containing loading/error states, your data (if the query has successfully executed), and a refetch callable that can be used to re-run the query. How can I provide arguments to my query function?

kwargs can be provided to your query function via the kwargs=... parameter.

components.py
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
How can I customize this hook's behavior?

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.py
from 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 or ForeignKey fields is enabled within the django_query_postprocessor. This is needed to prevent SynchronousOnlyOperation exceptions when accessing these fields within your ReactPy components.

However, if you...

  1. Want to use this hook to defer IO intensive tasks to be computed in the background
  2. Want to to utilize use_query with a different ORM

... then you can either set a custom postprocessor, or disable all postprocessing behavior by modifying the postprocessor=... parameter. In the example below, we will set the postprocessor to None to disable postprocessing behavior.

components.py
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 postprocessor, you will need to create a function where the first must be the query data. All proceeding arguments are optional postprocessor_kwargs (see below). This postprocessor function must return the modified data.

components.py
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 or ForeignKey fields is enabled within the django_query_postprocessor. This is needed to prevent SynchronousOnlyOperation 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 postprocessor (located at reactpy_django.utils.django_query_postprocessor) via the postprocessor_kwargs=... parameter.

components.py
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 _set by default.

Can I make ORM calls without hooks?

Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a SynchronousOnlyOperation exception.

These 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.

Can I make a failed query try again?

Yes, use_mutation can be re-executed by calling reset() on your use_mutation instance.

For example, take a look at reset_event below.

components.pymodels.py
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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
Why does the example query function return TodoItem.objects.all()?

This design decision was based on Apollo's useQuery hook, but ultimately helps avoid Django's SynchronousOnlyOperation exceptions.

With the Model or QuerySet your function returns, this hook uses the default postprocessor to ensure that all deferred or lazy fields are executed.

"},{"location":"reference/hooks/#use-mutation","title":"Use Mutation","text":"

Modify data in the background, typically to create/update/delete data from the Django ORM.

Mutation functions can return False to manually prevent your refetch=... function from executing. All other returns are ignored.

Mutation functions can be sync or async.

components.pymodels.py
from 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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
See Interface

Parameters

Name Type Description Default mutation Callable[FuncParams, bool | None] | Callable[FuncParams, Awaitable[bool | None]] A callable that performs Django ORM create, update, or delete functionality. If this function returns False, then your refetch function will not be used. N/A thread_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 your use_query hook) or a sequence of query functions that need a refetch if the mutation succeeds. This is useful for refreshing data after a mutation has been performed. None

Returns

Type Description Mutation[FuncParams] An object containing loading/error states, and a reset callable that will set loading/error states to defaults. This object can be called to run the query. How can I provide arguments to my mutation function?

*args and **kwargs can be provided to your mutation function via mutation(...) parameters.

components.py
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
How can I customize this hook's behavior?

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
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
Can I make ORM calls without hooks?

Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a SynchronousOnlyOperation exception.

These 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.

Can I make a failed mutation try again?

Yes, use_mutation can be re-executed by calling reset() on your use_mutation instance.

For example, take a look at reset_event below.

components.pymodels.py
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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
Can use_mutation trigger a refetch of use_query?

Yes, use_mutation can queue a refetch of a use_query via the refetch=... argument.

The example below is a merge of the use_query and use_mutation examples above with the addition of a use_mutation(refetch=...) argument.

Please note that refetch will cause all use_query hooks that use get_items in the current component tree will be refetched.

components.pymodels.py
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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
"},{"location":"reference/hooks/#use-user-data","title":"Use User Data","text":"

Store or retrieve a dict containing user data specific to the connection's User.

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 REACTPY_DATABASE.

components.py
from 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
See Interface

Parameters

Name Type Description Default default_data None | dict[str, Callable[[], Any] | Callable[[], Awaitable[Any]] | Any] A dictionary containing {key: default_value} pairs. For computationally intensive defaults, your default_value can be sync or async functions that return the value to set. None save_default_data bool If True, default_data values will automatically be stored within the database if they do not exist. False

Returns

Type Description UserData A NamedTuple containing a Query and Mutation objects used to access/modify user data. Read the use_query and use_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 {key: default_value} pairs. For computationally intensive defaults, your default_value can be sync or async functions that return the value to set.

components.py
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
"},{"location":"reference/hooks/#communication-hooks","title":"Communication Hooks","text":""},{"location":"reference/hooks/#use-channel-layer","title":"Use Channel Layer","text":"

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
from 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
See Interface

Parameters

Name Type Description Default name str | None The name of the channel to subscribe to. If you define a group_name, you can keep name 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 If True, the channel will automatically be added to the group when the component mounts. True group_discard bool If True, the channel will automatically be removed from the group when the component dismounts. True receiver AsyncMessageReceiver | None An async function that receives a message: 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 in settings.py:CHANNEL_LAYERS. 'default'

Returns

Type Description AsyncMessageSender An async callable that can send a message: dict. Extra Django configuration required

In 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:

  1. Install redis on your machine.

  2. Run the following command to install channels-redis in your Python environment.

    pip install channels-redis\n
  3. Configure your settings.py to use RedisChannelLayer 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
How do I broadcast a message to multiple components?

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 channel name while using groups, ReactPy will automatically generate a unique channel name for you.

In the example below, all messages sent by the sender component will be received by all receiver components that exist (across every active client browser).

components.py
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
How do I signal a re-render from something that isn't a component?

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 the get_channel_layer().send(...) to send the signal.

In the example below, the sender will signal every time ExampleModel is saved. Then, when the receiver gets this signal, it explicitly calls set_message(...) to trigger a re-render.

signals.pycomponents.py
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
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
"},{"location":"reference/hooks/#connection-hooks","title":"Connection Hooks","text":""},{"location":"reference/hooks/#use-connection","title":"Use Connection","text":"

Returns the active connection, which is either a Django WebSocket or a HTTP Request.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description Connection An object that contains a carrier (WebSocket or HttpRequest), scope, and location."},{"location":"reference/hooks/#use-scope","title":"Use Scope","text":"

Shortcut that returns the WebSocket or HTTP connection's scope.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description MutableMapping[str, Any] The connection's scope."},{"location":"reference/hooks/#use-location","title":"Use Location","text":"

Shortcut that returns the browser's current Location.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description Location An object containing the current URL's pathname and search 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 http://example.com.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description str | 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 a randomly generated uuid4. It is notable to mention that it is persistent across the current connection. The uuid is reset when the page is refreshed.

This is useful when used in combination with use_channel_layer to send messages to a specific component instance, and/or retain a backlog of messages in case that component is disconnected via use_channel_layer( ... , group_discard=False).

components.py
from 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
See Interface

Parameters

None

Returns

Type Description str A string containing the root component's id."},{"location":"reference/hooks/#use-user","title":"Use User","text":"

Shortcut that returns the WebSocket or HTTP connection's User.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description AbstractUser A Django User, which can also be an AnonymousUser."},{"location":"reference/html/","title":"HTML","text":""},{"location":"reference/html/#overview","title":"Overview","text":"

We supply some HTML elements can be used to help simplify development.

"},{"location":"reference/html/#pyscript","title":"PyScript","text":"

PyScript code block. The text content of this tag are executed within the PyScript interpreter. This can be used as an alternative to the reactpy.html.script.

This is a primitive HTML tag that is leveraged by reactpy_django.components.pyscript_component.

The pyscript tag functions identically to HTML tags contained within reactpy.html.

components.pymy_template.html
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
{% 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
You must call pyscript_setup in your Django template before using this tag!

This requires using of the {% pyscript_setup %} template tag to initialize PyScript on the client.

my_template.html
{% load reactpy %}\n\n<head>\n    <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
"},{"location":"reference/management-commands/","title":"Management Commands","text":""},{"location":"reference/management-commands/#overview","title":"Overview","text":"

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 expired ReactPy data from the database and/or cache.

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

python manage.py clean_reactpy\n
See Interface

Type python manage.py clean_reactpy --help to see the available options.

"},{"location":"reference/router/","title":"URL Router","text":""},{"location":"reference/router/#overview","title":"Overview","text":"

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 reactive-python/reactpy-router.

"},{"location":"reference/router/#django-router","title":"Django Router","text":"

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 will always handle the initial load of the webpage.

You can duplicate all your URL patterns within both Django and ReactPy, but it's easiest to use a wildcard .* within Django's urlpatterns and let ReactPy handle the rest. For example...

urlpatterns = [\n    re_path(r\"^.*$\", my_reactpy_router_view),\n]\n
components.py
from 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
See Interface

Parameters

Name Type Description Default *routes Route An object from reactpy-router containing a path, element, and child *routes. N/A

Returns

Type Description VdomDict | None The matched component/path after it has been fully rendered. How is this different from reactpy_router.simple.router?

This component utilizes reactpy-router under the hood, but provides a more Django-like URL routing syntax.

"},{"location":"reference/settings/","title":"Settings","text":""},{"location":"reference/settings/#overview","title":"Overview","text":"

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 REACTPY_DEFAULT_QUERY_POSTPROCESSOR to None to disable the default postprocessor.

"},{"location":"reference/settings/#reactpy_auth_backend","title":"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:

  1. You are using settings.py:REACTPY_AUTO_RELOGIN=True and...
  2. You are using AuthMiddlewareStack and...
  3. You are using Django's AUTHENTICATION_BACKENDS setting and...
  4. Your Django user model does not define a backend attribute.
"},{"location":"reference/settings/#reactpy_auto_relogin","title":"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 last_login timestamps and refresh the Django login session.

"},{"location":"reference/settings/#performance-settings","title":"Performance Settings","text":""},{"location":"reference/settings/#reactpy_database","title":"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
DATABASE_ROUTERS = [\"reactpy_django.database.Router\", ...]\n
"},{"location":"reference/settings/#reactpy_cache","title":"REACTPY_CACHE","text":"

Default: \"default\"

Example Value(s): \"my-reactpy-cache\"

Cache used by ReactPy, typically for caching disk operations.

We recommend using redis, memcache, or local-memory caching.

"},{"location":"reference/settings/#reactpy_backhaul_thread","title":"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 and uvicorn.

This setting is incompatible with daphne.

"},{"location":"reference/settings/#reactpy_default_hosts","title":"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 host argument in your template tag to manually override this default.

"},{"location":"reference/settings/#reactpy_prerender","title":"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:

  1. Only the component's first paint is pre-rendered.
  2. All connection hooks will provide HTTP variants.
  3. The component will be non-interactive until a WebSocket connection is formed.
  4. The component is re-rendered once a WebSocket connection is formed.

You can use the prerender argument in your template tag to manually override this default.

"},{"location":"reference/settings/#stability-settings","title":"Stability Settings","text":""},{"location":"reference/settings/#reactpy_reconnect_interval","title":"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 1.

"},{"location":"reference/settings/#reactpy_reconnect_max_interval","title":"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 REACTPY_RECONNECT_BACKOFF_MULTIPLIER can increase the time between reconnection attempts.

"},{"location":"reference/settings/#reactpy_reconnect_max_retries","title":"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 0 to not store any session data.

"},{"location":"reference/settings/#auto-clean-settings","title":"Auto-Clean Settings","text":""},{"location":"reference/settings/#reactpy_clean_interval","title":"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 None to disable automatic clean up operations.

"},{"location":"reference/settings/#reactpy_clean_sessions","title":"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 User delete operation.

"},{"location":"reference/template-tag/","title":"Template Tag","text":""},{"location":"reference/template-tag/#overview","title":"Overview","text":"

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 server-side ReactPy components onto your page.

Each component loaded via this template tag will receive a dedicated WebSocket connection to the server.

my_template.html
{% 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
See Interface

Parameters

Name Type Description Default dotted_path str The dotted path to the component to render. N/A *args Any The positional arguments to provide to the component. N/A class 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. Using key 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, this offline 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 path

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 register_component function to manually register your components.

Can I use multiple components on one page?

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.my_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 <body> tag.

Can I use positional arguments instead of keyword arguments?

You can use any combination of *args/**kwargs in your template tag.

my_template.htmlcomponents.py
{% component \"example_project.my_app.components.frog_greeter\" 123 \"Mr. Froggles\" species=\"Grey Treefrog\" %}\n
from reactpy import component\n\n\n@component\ndef frog_greeter(number, name, species=\"\"):\n    return f\"Hello #{number}, {name} the {species}!\"\n
Can I render components on a different server (distributed computing)?

Yes! This is most commonly done through settings.py:REACTPY_HOSTS. However, you can use the host keyword to render components on a specific ASGI server.

my_template.html
...\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:

  1. If your host address are completely separate ( origin1.com != origin2.com ) you will need to configure CORS headers on your main application during deployment.
  2. You will not need to register ReactPy WebSocket or HTTP paths on any applications that do not perform any component rendering.
  3. Your component will only be able to access your template tag's *args/**kwargs if your applications share a common database.
How do I pre-render components for SEO compatibility?

This is most commonly done through settings.py:REACTPY_PRERENDER. However, you can use the prerender keyword to pre-render a specific component.

my_template.html
...\n{% component \"example_project.my_app.components.do_something\" prerender=\"true\" %}\n...\n
How do I display something when the client disconnects?

You can use the offline keyword to display a specific component when the client disconnects from the server.

my_template.html
...\n{% component \"example_project.my_app.components.do_something\" offline=\"example_project.my_app.components.offline\" %}\n...\n

Note: The offline component will be non-interactive (hooks won't operate).

"},{"location":"reference/template-tag/#pyscript-component","title":"PyScript Component","text":"

This template tag can be used to insert any number of client-side ReactPy components onto your page.

By default, the only available dependencies are the Python standard library, pyscript, pyodide, reactpy core.

The entire file path provided is loaded directly into the browser, and must have a def root() component to act as the entry point.

Pitfall

Similar to JavaScript, your provided Python file is loaded directly into the client (web browser) as raw text to run using the PyScript interpreter. Be cautious about what you include in your Python file.

As a result being client-sided, Python packages within your local environment (such as those installed via pip install ...) are not accessible within PyScript components.

my_template.htmlhello_world.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/hello_world.py\" %}\n</body>\n\n</html>\n
from reactpy import component, html\n\n\n@component\ndef root():\n    return html.div(\"Hello, World!\")\n
See Interface

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/A initial str | VdomDict | ComponentType The initial HTML that is displayed prior to the PyScript component loads. This can either be a string containing raw HTML, a reactpy.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 several options available to execute JavaScript, including...

  • Pyodide's js module
  • Pyscript's foreign function interface
  • Pyscript's JavaScript modules.

Pyodide JS Module

The Pyodide js 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, you will need to be mindful of JavaScript load order if using async or deferred loading!

root.py
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

PyScript FFI

...

PyScript JS Modules

Assuming you have a local bundle stored within your project's static files, you can import JavaScript modules in a fashion similar to import {moment} from 'static/moment.js'. You will first need to configure your {% pyscript_setup %} block to make the moment.js module available to PyScript. Then, this module can be accessed within pyscript.js_modules.*.

root.pymy_template.html
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
{% 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
Does my entire component need to be contained in one file?

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
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
How do I display something while the component is loading?

You can configure the initial keyword to display HTML while your PyScript component is loading.

The value for initial is most commonly be a string containing raw HTML.

my_template.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 reactpy.html snippet or a non-interactive @component via template context.

my_template.htmlviews.py
<body>\n{% pyscript_component \"./example_project/my_app/components/root.py\" initial=my_initial_object %}\n</body>\n
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
Can I use a different name for my root component?

Yes, you can use the root keyword to specify a different name for your root function.

my_template.htmlmain.py
<body>\n{% pyscript_component \"./example_project/my_app/components/main.py\" root=\"main\" %}\n</body>\n
from reactpy import component, html\n\n\n@component\ndef main():\n    return html.div(\"Hello, World!\")\n
"},{"location":"reference/template-tag/#pyscript-setup","title":"PyScript Setup","text":"

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
{% load reactpy %}\n\n<head>\n    <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
See Interface

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/A extra_js str | dict A JSON string or Python dictionary containing a vanilla JavaScript module URL and the name: str to access it within pyscript.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
<head>\n    <title>ReactPy</title>\n{% pyscript_setup \"dill==0.3.5\" \"markdown<=3.6.0\" \"nest_asyncio\" \"titlecase\" %}\n</head>\n
How do I install additional Javascript dependencies?

You can use the extra_js keyword to load additional JavaScript modules into your PyScript environment.

my_template.htmlviews.py
{% 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 extra_js is most commonly a Python dictionary, but JSON strings are also supported.

my_template.html
{% 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
How do I modify the pyscript default configuration?

You can modify the default PyScript configuration by providing a value to the config keyword.

my_template.html
<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
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
"},{"location":"reference/utils/","title":"Utilities","text":""},{"location":"reference/utils/#overview","title":"Overview","text":"

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 Django view as a ReactPy iframe.

It is mandatory to use this function alongside view_to_iframe.

apps.py
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
See Interface

Parameters

Name Type Description Default view Callable | View | str The view to register. Can be a function or class based view, or a dotted path to a view. N/A

Returns

None

Only use this within AppConfig.ready()

You should always call register_iframe within a Django AppConfig.ready() method. This ensures you will retain multiprocessing compatibility, such as with ASGI web server workers.

"},{"location":"reference/utils/#register-component","title":"Register Component","text":"

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
from 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
See Interface

Parameters

Name Type Description Default component ComponentConstructor | str The component to register. Can be a component function or dotted path to a component. N/A

Returns

None

Only use this within MyAppConfig.ready()

You should always call register_component within a Django MyAppConfig.ready() method. This ensures you will retain multiprocessing compatibility, such as with ASGI web server workers.

Do I need to use this?

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 host to a dedicated Django rendering application that doesn't have templates.

"},{"location":"reference/utils/#django-query-postprocessor","title":"Django Query Postprocessor","text":"

This is the default postprocessor for the use_query hook.

Since ReactPy is rendered within an asyncio loop, this postprocessor is exists to prevent Django's SynchronousOnlyException by recursively prefetching fields within Django's ORM. Note that this effectively eliminates Django's lazy execution behavior.

components.pymodels.py
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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
See Interface

Parameters

Name Type Description Default data QuerySet | Model The Model or QuerySet to recursively fetch fields from. N/A many_to_many bool Whether or not to recursively fetch ManyToManyField relationships. True many_to_one bool Whether or not to recursively fetch ForeignKey relationships. True

Returns

Type Description QuerySet | Model The Model or QuerySet 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":""},{"location":"about/changelog/#changed","title":"Changed","text":"
  • Now using ReactPy-Router v1 for URL routing, which comes with a slightly different API than before.
  • Removed dependency on aiofile.
"},{"location":"about/changelog/#removed","title":"Removed","text":"
  • Removed the following deprecated features:
    • The compatibility argument on reactpy_django.components.view_to_component
    • reactpy_django.components.view_to_component usage as a decorator
    • reactpy_django.decorators.auth_required
    • reactpy_django.REACTPY_WEBSOCKET_PATH
    • settings.py:REACTPY_WEBSOCKET_URL
"},{"location":"about/changelog/#400-2024-06-22","title":"4.0.0 - 2024-06-22","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
  • 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.
"},{"location":"about/changelog/#changed_1","title":"Changed","text":"
  • New syntax for use_query and use_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
"},{"location":"about/changelog/#removed_1","title":"Removed","text":"
  • QueryOptions and MutationOptions have been removed. The value contained within these objects are now passed directly into the hook.
"},{"location":"about/changelog/#fixed","title":"Fixed","text":"
  • Resolved a bug where Django-ReactPy would not properly detect settings.py:DEBUG.
"},{"location":"about/changelog/#381-2024-05-07","title":"3.8.1 - 2024-05-07","text":""},{"location":"about/changelog/#added_1","title":"Added","text":"
  • Python 3.12 compatibility
"},{"location":"about/changelog/#380-2024-02-20","title":"3.8.0 - 2024-02-20","text":""},{"location":"about/changelog/#added_2","title":"Added","text":"
  • Built-in cross-process communication mechanism via the reactpy_django.hooks.use_channel_layer hook.
  • Access to the root component's id via the reactpy_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.
"},{"location":"about/changelog/#changed_2","title":"Changed","text":"
  • Simplified code for cascading deletion of user data.
"},{"location":"about/changelog/#370-2024-01-30","title":"3.7.0 - 2024-01-30","text":""},{"location":"about/changelog/#added_3","title":"Added","text":"
  • An \"offline component\" can now be displayed when the client disconnects from the server.
  • URL router now supports a * wildcard to create default routes.
"},{"location":"about/changelog/#360-2024-01-10","title":"3.6.0 - 2024-01-10","text":""},{"location":"about/changelog/#added_4","title":"Added","text":"
  • 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 to True 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 views view_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 update last_login timestamps and refresh the Django login session.
"},{"location":"about/changelog/#changed_3","title":"Changed","text":"
  • Renamed undocumented utility function ComponentPreloader to RootComponentFinder.
  • It is now recommended to call as_view() when using view_to_component or view_to_iframe with Class Based Views.
  • For thread safety, thread_sensitive=True has been enabled in all sync_to_async functions where ORM queries are possible.
  • reactpy_django.hooks.use_mutation now has a __call__ method. So rather than writing my_mutation.execute(...), you can now write my_mutation(...).
"},{"location":"about/changelog/#deprecated","title":"Deprecated","text":"
  • The compatibility argument on reactpy_django.components.view_to_component is deprecated.
    • Use view_to_iframe as a replacement.
  • 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.
  • 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).
"},{"location":"about/changelog/#fixed_1","title":"Fixed","text":"
  • Fixed a bug where exception stacks would not print on failed component renders.
"},{"location":"about/changelog/#351-2023-09-07","title":"3.5.1 - 2023-09-07","text":""},{"location":"about/changelog/#added_5","title":"Added","text":"
  • Warning W018 (Suspicious position of 'reactpy_django' in INSTALLED_APPS) has been added.
"},{"location":"about/changelog/#changed_4","title":"Changed","text":"
  • The default postprocessor can now disabled by setting REACTPY_DEFAULT_QUERY_POSTPROCESSOR to None.
  • Massive overhaul of docs styling.
"},{"location":"about/changelog/#350-2023-08-26","title":"3.5.0 - 2023-08-26","text":""},{"location":"about/changelog/#added_6","title":"Added","text":"
  • 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!
"},{"location":"about/changelog/#changed_5","title":"Changed","text":"
  • 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 if settings.py:DEBUG is enabled.
  • Bumped the minimum @reactpy/client version to 0.3.1
  • Use TypeScript instead of JavaScript for this repository.
  • Bumped the minimum Django version to 4.2.
Django 4.2+ is required

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_2","title":"Removed","text":"
  • settings.py:REACTPY_RECONNECT_MAX is removed. See the docs for the new REACTPY_RECONNECT_* settings.
"},{"location":"about/changelog/#340-2023-08-18","title":"3.4.0 - 2023-08-18","text":""},{"location":"about/changelog/#added_7","title":"Added","text":"
  • 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 the component 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.
"},{"location":"about/changelog/#changed_6","title":"Changed","text":"
  • 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.
"},{"location":"about/changelog/#deprecated_1","title":"Deprecated","text":"
  • reactpy_django.REACTPY_WEBSOCKET_PATH is deprecated. The identical replacement is REACTPY_WEBSOCKET_ROUTE.
  • settings.py:REACTPY_WEBSOCKET_URL is deprecated. The similar replacement is REACTPY_URL_PREFIX.
"},{"location":"about/changelog/#removed_3","title":"Removed","text":"
  • 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 of channels do not require installation via INSTALLED_APPS to receive an ASGI web server.
"},{"location":"about/changelog/#332-2023-08-13","title":"3.3.2 - 2023-08-13","text":""},{"location":"about/changelog/#added_8","title":"Added","text":"
  • ReactPy WebSocket will now decode messages via orjson resulting in an ~6% overall performance improvement.
  • Built-in asyncio event loops are now patched via nest_asyncio, resulting in an ~10% overall performance improvement. This has no performance impact if you are running your web server with uvloop.
"},{"location":"about/changelog/#fixed_2","title":"Fixed","text":"
  • 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 by uvicorn when REACTPY_BACKHAUL_THREAD = True.
  • Fixed bug on Windows where rendering behavior would be jittery with daphne when REACTPY_BACKHAUL_THREAD = True.
"},{"location":"about/changelog/#331-2023-08-08","title":"3.3.1 - 2023-08-08","text":""},{"location":"about/changelog/#added_9","title":"Added","text":"
  • Additional system checks for ReactPy misconfigurations.
"},{"location":"about/changelog/#changed_7","title":"Changed","text":"
  • REACTPY_BACKHAUL_THREAD now defaults to False.
"},{"location":"about/changelog/#330-2023-08-05","title":"3.3.0 - 2023-08-05","text":""},{"location":"about/changelog/#added_10","title":"Added","text":"
  • Added system checks for a variety of common ReactPy misconfigurations.
  • REACTPY_BACKHAUL_THREAD setting to enable/disable threading behavior.
"},{"location":"about/changelog/#changed_8","title":"Changed","text":"
  • If using settings.py:REACTPY_DATABASE, reactpy_django.database.Router must now be registered in settings.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.
"},{"location":"about/changelog/#321-2023-06-29","title":"3.2.1 - 2023-06-29","text":""},{"location":"about/changelog/#added_11","title":"Added","text":"
  • Template tag exception details are now rendered on the webpage when settings.py:DEBUG is enabled.
"},{"location":"about/changelog/#fixed_3","title":"Fixed","text":"
  • Prevent exceptions within the component template tag from causing the whole template to fail to render.
"},{"location":"about/changelog/#320-2023-06-08","title":"3.2.0 - 2023-06-08","text":""},{"location":"about/changelog/#added_12","title":"Added","text":"
  • 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.
"},{"location":"about/changelog/#changed_9","title":"Changed","text":"
  • Using SessionMiddlewareStack is now optional.
  • Using AuthMiddlewareStack is now optional.
"},{"location":"about/changelog/#310-2023-05-06","title":"3.1.0 - 2023-05-06","text":""},{"location":"about/changelog/#added_13","title":"Added","text":"
  • 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 accepts reactpy_django.types.MutationOptions option to customize how mutations are executed.
"},{"location":"about/changelog/#changed_10","title":"Changed","text":"
  • The mutate argument on reactpy_django.hooks.use_mutation has been renamed to mutation.
"},{"location":"about/changelog/#fixed_4","title":"Fixed","text":"
  • Fix bug where ReactPy utilizes Django's default cache timeout, which can prematurely expire the component cache.
"},{"location":"about/changelog/#301-2023-04-06","title":"3.0.1 - 2023-04-06","text":""},{"location":"about/changelog/#changed_11","title":"Changed","text":"
  • reactpy-django database entries are no longer cleaned during Django application startup. Instead, it will occur on webpage loads if REACTPY_RECONNECT_MAX seconds has elapsed since the last cleaning.
"},{"location":"about/changelog/#300-reactpy-2023-03-30","title":"3.0.0-reactpy - 2023-03-30","text":""},{"location":"about/changelog/#changed_12","title":"Changed","text":"
  • django-idom has been renamed to reactpy-django! Please note that all references to the word idom in your code should be changed to reactpy. See the docs for more details.
"},{"location":"about/changelog/#300-2023-03-08","title":"3.0.0 - 2023-03-08","text":"Note

This is Django-IDOM's biggest update yet!

To upgrade from previous version you will need to...

  1. Install django-idom >= 3.0.0
  2. Run idom rewrite-keys <DIR> and idom rewrite-camel-case-props <DIR> to update your idom.html.* calls to the new syntax
  3. Run python manage.py migrate to create the new Django-IDOM database entries
"},{"location":"about/changelog/#added_14","title":"Added","text":"
  • The idom client will automatically configure itself to debug mode depending on settings.py:DEBUG.
  • use_connection hook for returning the browser's active Connection.
  • IDOM_CACHE is now configurable within settings.py to whatever cache name you wish.
"},{"location":"about/changelog/#changed_13","title":"Changed","text":"
  • 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 example className now becomes class_name.
    • key=... is now declared within the props dict (rather than as a kwarg).
  • 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 to IDOM_RECONNECT_MAX.
"},{"location":"about/changelog/#removed_4","title":"Removed","text":"
  • django_idom.hooks.use_websocket has been removed. The similar replacement is django_idom.hooks.use_connection.
  • django_idom.types.IdomWebsocket has been removed. The similar replacement is django_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 the IDOM_CACHE setting.
"},{"location":"about/changelog/#fixed_5","title":"Fixed","text":"
  • view_to_component will now retain the contents of a <head> tag when rendering.
  • React client is now set to production rather than development.
  • use_query will now utilize field.related_name when postprocessing many-to-one relationships.
"},{"location":"about/changelog/#security","title":"Security","text":"
  • 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.
"},{"location":"about/changelog/#221-2023-01-09","title":"2.2.1 - 2023-01-09","text":""},{"location":"about/changelog/#fixed_6","title":"Fixed","text":"
  • 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.
"},{"location":"about/changelog/#220-2022-12-28","title":"2.2.0 - 2022-12-28","text":""},{"location":"about/changelog/#added_15","title":"Added","text":"
  • Add options: QueryOptions parameter to use_query to allow for configuration of this hook.
"},{"location":"about/changelog/#changed_14","title":"Changed","text":"
  • By default, use_query will recursively prefetch all many-to-many or many-to-one relationships to prevent SynchronousOnlyOperation exceptions.
"},{"location":"about/changelog/#removed_5","title":"Removed","text":"
  • django_idom.hooks._fetch_lazy_fields has been deleted. The equivalent replacement is django_idom.utils.django_query_postprocessor.
"},{"location":"about/changelog/#210-2022-11-01","title":"2.1.0 - 2022-11-01","text":""},{"location":"about/changelog/#changed_15","title":"Changed","text":"
  • Minimum channels version is now 4.0.0.
"},{"location":"about/changelog/#fixed_7","title":"Fixed","text":"
  • Change type hint on view_to_component callable to have request 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))
"},{"location":"about/changelog/#security_1","title":"Security","text":"
  • Add note to docs about potential information exposure via view_to_component when using compatibility=True.
"},{"location":"about/changelog/#201-2022-10-18","title":"2.0.1 - 2022-10-18","text":""},{"location":"about/changelog/#fixed_8","title":"Fixed","text":"
  • Ability to use key=... parameter on all prefabricated components.
"},{"location":"about/changelog/#200-2022-10-17","title":"2.0.0 - 2022-10-17","text":""},{"location":"about/changelog/#added_16","title":"Added","text":"
  • use_origin hook for returning the browser's location.origin.
"},{"location":"about/changelog/#changed_16","title":"Changed","text":"
  • view_to_component now returns a Callable, instead of directly returning a Component. Check the docs for new usage info.
  • use_mutation and use_query will now log any query failures.
"},{"location":"about/changelog/#fixed_9","title":"Fixed","text":"
  • Allow use_mutation to have refetch=None, as the docs suggest is possible.
  • use_query will now prefetch all fields to prevent SynchronousOnlyOperation exceptions.
  • view_to_component, django_css, and django_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
"},{"location":"about/changelog/#120-2022-09-19","title":"1.2.0 - 2022-09-19","text":""},{"location":"about/changelog/#added_17","title":"Added","text":"
  • 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.
"},{"location":"about/changelog/#changed_17","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.40.2
  • Testing suite now uses playwright instead of selenium
"},{"location":"about/changelog/#fixed_10","title":"Fixed","text":"
  • IDOM preloader is no longer sensitive to whitespace within template tags.
"},{"location":"about/changelog/#110-2022-07-01","title":"1.1.0 - 2022-07-01","text":""},{"location":"about/changelog/#added_18","title":"Added","text":"
  • django_css and django_js components to defer loading CSS & JS files until needed.
"},{"location":"about/changelog/#changed_18","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.39.0
"},{"location":"about/changelog/#100-2022-05-22","title":"1.0.0 - 2022-05-22","text":""},{"location":"about/changelog/#added_19","title":"Added","text":"
  • Django specific hooks! use_websocket, use_scope, and use_location are now available within the django_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.
"},{"location":"about/changelog/#changed_19","title":"Changed","text":"
  • idom_component template tag has been renamed to component
  • Bumped the minimum IDOM version to 0.38.0
"},{"location":"about/changelog/#removed_6","title":"Removed","text":"
  • websocket parameter for components has been removed. Functionally, it is replaced with django_idom.hooks.use_websocket.
"},{"location":"about/changelog/#005-2022-04-04","title":"0.0.5 - 2022-04-04","text":""},{"location":"about/changelog/#changed_20","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.37.2
"},{"location":"about/changelog/#fixed_11","title":"Fixed","text":"
  • ModuleNotFoundError: No module named idom.core.proto caused by IDOM 0.37.2
"},{"location":"about/changelog/#004-2022-03-05","title":"0.0.4 - 2022-03-05","text":""},{"location":"about/changelog/#changed_21","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.37.1
"},{"location":"about/changelog/#003-2022-02-19","title":"0.0.3 - 2022-02-19","text":""},{"location":"about/changelog/#changed_22","title":"Changed","text":"
  • Bumped the minimum IDOM version to 0.36.3
"},{"location":"about/changelog/#002-2022-01-30","title":"0.0.2 - 2022-01-30","text":""},{"location":"about/changelog/#added_20","title":"Added","text":"
  • Ability to declare the HTML class of the top-level component div
  • name = ... parameter to IDOM HTTP paths for use with django.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
"},{"location":"about/changelog/#changed_23","title":"Changed","text":"
  • 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
"},{"location":"about/changelog/#removed_7","title":"Removed","text":"
  • IDOM_WEB_MODULES_PATH has been replaced with Django include(...)
  • IDOM_WS_MAX_RECONNECT_DELAY has been renamed to IDOM_WS_MAX_RECONNECT_TIMEOUT
  • idom_web_modules cache back-end has been renamed to idom
"},{"location":"about/changelog/#fixed_12","title":"Fixed","text":"
  • Increase test timeout values to prevent false positives
  • Windows compatibility for building Django-IDOM
"},{"location":"about/changelog/#security_2","title":"Security","text":"
  • Fixed potential directory traversal attack on the IDOM web modules URL
"},{"location":"about/changelog/#001-2021-08-18","title":"0.0.1 - 2021-08-18","text":""},{"location":"about/changelog/#added_21","title":"Added","text":"
  • Support for IDOM within the Django
"},{"location":"about/code/","title":"Code","text":""},{"location":"about/code/#overview","title":"Overview","text":"

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 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.

"},{"location":"about/code/#creating-an-environment","title":"Creating an environment","text":"

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:

  1. When pip install is run on the reactpy-django package.
  2. Every time python manage.py ... or nox ... is run
"},{"location":"about/code/#running-the-full-test-suite","title":"Running the full test suite","text":"

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:

nox -t test -- --headless\n
"},{"location":"about/code/#running-django-tests","title":"Running Django tests","text":"

If you want to only run our Django tests in your current environment, you can use the following command:

cd tests\npython manage.py test\n
"},{"location":"about/code/#running-django-test-web-server","title":"Running Django test web server","text":"

If you want to manually run the Django test application, you can use the following command:

cd tests\npython manage.py runserver\n
"},{"location":"about/code/#creating-a-pull-request","title":"Creating a pull request","text":"

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 http://127.0.0.1:8000 to view a preview of the documentation.

"},{"location":"about/docs/#github-pull-request","title":"GitHub Pull Request","text":"

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.

pip install reactpy-django\n
"},{"location":"learn/add-reactpy-to-a-django-project/#step-2-configure-settingspy","title":"Step 2: Configure settings.py","text":"

Add \"reactpy_django\" to INSTALLED_APPS in your settings.py file.

settings.py
INSTALLED_APPS = [\n    ...,\n    \"reactpy_django\",\n]\n
Enable ASGI and Django Channels (Required)

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 and channels installation docs:

  1. Install channels[daphne]
  2. Add \"daphne\" to INSTALLED_APPS.

    INSTALLED_APPS = [\n    \"daphne\",\n    ...,\n]\n
  3. Set your ASGI_APPLICATION variable.

    ASGI_APPLICATION = \"example_project.asgi.application\"\n
Configure ReactPy settings (Optional)

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: Configure urls.py","text":"

Add ReactPy HTTP paths to your urlpatterns in your urls.py file.

urls.py
from django.urls import include, path\n\nurlpatterns = [\n    ...,\n    path(\"reactpy/\", include(\"reactpy_django.http.urls\")),\n]\n
"},{"location":"learn/add-reactpy-to-a-django-project/#step-4-configure-asgipy","title":"Step 4: Configure asgi.py","text":"

Register ReactPy's WebSocket using REACTPY_WEBSOCKET_ROUTE in your asgi.py file.

asgi.py
import 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
Add AuthMiddlewareStack (Optional)

There are many situations where you need to access the Django User or Session objects within ReactPy components. For example, if you want to:

  1. Access the User that is currently logged in
  2. Access Django's Session object
  3. Login or logout the current User

In these situations will need to ensure you are using AuthMiddlewareStack.

from 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
Where is my asgi.py?

If you do not have an asgi.py, follow the channels installation guide.

"},{"location":"learn/add-reactpy-to-a-django-project/#step-5-run-database-migrations","title":"Step 5: Run database migrations","text":"

Run Django's migrate command to initialize ReactPy-Django's database table.

python manage.py migrate\n
"},{"location":"learn/add-reactpy-to-a-django-project/#step-6-check-your-configuration","title":"Step 6: Check your configuration","text":"

Run Django's check command to verify if ReactPy was set up correctly.

python manage.py check\n
"},{"location":"learn/add-reactpy-to-a-django-project/#step-7-create-your-first-component","title":"Step 7: Create your first component","text":"

The next page 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 simple hello_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 and kwargs into your component function. After reading the code below, pay attention to how the function definition for hello_world (from the previous example) accepts a recipient argument.

{% 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
"},{"location":"learn/your-first-component/","title":"Your First Component","text":""},{"location":"learn/your-first-component/#overview","title":"Overview","text":"

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:

  1. You have a Django app named my_app, which was created by Django's startapp command.
  2. You have placed my_app directly into your Django project folder (./example_project/my_app). This is common for small projects.
How do I organize my Django project for ReactPy?

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 will define your component function(s) using the @component decorator.

components.py
from reactpy import component, html\n\n@component\ndef hello_world(recipient: str):\n    return html.h1(f\"Hello {recipient}!\")\n
What should I name my ReactPy files and functions?

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 as components/navbar.py.

Ultimately, components are referenced by Python dotted path in my_template.html (see next step). This dotted path must be valid to Python's importlib.

What does the decorator actually do?

While not all components need to be decorated, there are a few features this decorator adds to your components.

  1. 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).
  2. The ability to use hooks.
    • The decorator is required on any component where hooks are defined.
  3. Scoped failures.
    • If a decorated component generates an exception, then only that one component will fail to render.
"},{"location":"learn/your-first-component/#embedding-in-a-template","title":"Embedding in a template","text":"

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 and kwargs into your component function. After reading the code below, pay attention to how the function definition for hello_world (from the previous step) accepts a recipient argument.

my_template.html
{% 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 automatically registered!

ReactPy-Django will automatically register any component that is referenced in a Django HTML template. This means you typically do not need to manually register components in your Django app.

Please note that this HTML template must be properly stored within a registered Django app. ReactPy-Django will output a console log message containing all detected components when the server starts up.

Do not use context variables for the component path

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 register_component function to manually register your components.

Can I use multiple components on one page?

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.my_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 <body> tag.

Where is my templates folder?

If you do not have a ./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 to settings.py:INSTALLED_APPS.

"},{"location":"learn/your-first-component/#setting-up-a-django-view","title":"Setting up a Django view","text":"

Within your Django app's views.py file, you will need to create a view function to render the HTML template my_template.html (from the previous step).

views.py
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.py and define what URL it should be accessible at.

urls.py
from django.urls import path\nfrom example import views\n\nurlpatterns = [\n    path(\"example/\", views.index),\n]\n
Which urls.py do I add my views to?

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 urls.py you will use Django's include function to link it all together.

"},{"location":"learn/your-first-component/#viewing-your-component","title":"Viewing your component","text":"

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 use manage.py runserver for production

This 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 available dependencies are the Python standard library, pyscript, pyodide, reactpy core.

The entire file path provided is loaded directly into the browser, and must have a def root() component to act as the entry point.

Pitfall

Similar to JavaScript, your provided Python file is loaded directly into the client (web browser) as raw text to run using the PyScript interpreter. Be cautious about what you include in your Python file.

As a result being client-sided, Python packages within your local environment (such as those installed via pip install ...) are not accessible within PyScript components.

components.pyroot.pymy_template.html
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
{% 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
See Interface

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/A initial str | VdomDict | ComponentType The initial HTML that is displayed prior to the PyScript component loads. This can either be a string containing raw HTML, a reactpy.html snippet, or a non-interactive component. \"\" root str The name of the root component function. \"root\" You must call pyscript_setup in your Django template before using this tag!

This requires using of the {% pyscript_setup %} template tag to initialize PyScript on the client.

my_template.html
{% load reactpy %}\n\n<head>\n    <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
How do I execute JavaScript within PyScript components?

PyScript components several options available to execute JavaScript, including...

  • Pyodide's js module
  • Pyscript's foreign function interface
  • Pyscript's JavaScript modules.

Pyodide JS Module

The Pyodide js 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, you will need to be mindful of JavaScript load order if using async or deferred loading!

root.py
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

PyScript FFI

...

PyScript JS Modules

Assuming you have a local bundle stored within your project's static files, you can import JavaScript modules in a fashion similar to import {moment} from 'static/moment.js'. You will first need to configure your {% pyscript_setup %} block to make the moment.js module available to PyScript. Then, this module can be accessed within pyscript.js_modules.*.

root.pymy_template.html
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
{% 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
Does my entire component need to be contained in one file?

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.py
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            \"./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
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
How do I display something while the component is loading?

You can configure the initial keyword to display HTML while your PyScript component is loading.

The value for initial is most commonly be a reactpy.html snippet or a non-interactive @component.

components.py
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
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
Can I use a different name for my root component?

Yes, you can use the root keyword to specify a different name for your root function.

components.pymain.py
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
from reactpy import component, html\n\n\n@component\ndef main():\n    return html.div(\"Hello, World!\")\n
"},{"location":"reference/components/#view-to-component","title":"View To Component","text":"

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.py
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
See Interface

Parameters

Name Type Description Default view Callable | View | str The view to convert, or the view's dotted path as a string. N/A transforms 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 If True, an exception will be generated if the HTML does not perfectly adhere to HTML5. True

Returns

Type Description constructor A function that takes request, *args, key, **kwargs and returns a ReactPy component. Note that *args and **kwargs are directly provided to your view. Existing limitations

There 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.
How do I use this for Class Based Views?

Class Based Views are accepted by view_to_component as an argument.

Calling as_view() is optional, but recommended.

components.pyviews.py
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
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 provide request, args, and kwargs to a converted view?

This component accepts request, *args, and **kwargs arguments, which are sent to your provided view.

components.pyviews.py
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
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
How do I customize this component's behavior?

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 strict_parsing parameter to False. This uses libxml2 recovery algorithm, which is designed to be similar to how web browsers would attempt to parse non-standard or broken HTML.

components.pyviews.py
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 your transforms 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 id, you can create a transform like such:

components.pyviews.py
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
from django.http import HttpResponse\n\n\ndef hello_world(request):\n    return HttpResponse('<div id=\"hello-world\"> Hello World! </div>')\n
"},{"location":"reference/components/#view-to-iframe","title":"View To Iframe","text":"

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 than view_to_component, it comes with different limitations.

Compatible with sync or async Function Based Views and Class Based Views.

components.pyviews.pyapps.py
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.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
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
See Interface

Parameters

Name Type Description Default view Callable | View | str The view function or class to convert. N/A extra_props Mapping[str, Any] | None Additional properties to add to the iframe element. None

Returns

Type Description constructor A function that takes *args, key, **kwargs and returns a ReactPy component. Note that *args and **kwargs are directly provided to your view. Existing limitations

There 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.
How do I use this for Class Based Views?

Class Based Views are accepted by view_to_iframe as an argument.

Calling as_view() is optional, but recommended.

components.pyviews.pyapps.py
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
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.HelloWorld)\n
How do I provide args and kwargs to a converted view?

This component accepts *args and **kwargs arguments, which are sent to your provided view.

All provided *args and *kwargs must be serializable values, since they are encoded into the URL.

components.pyviews.pyapps.py
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
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
How do I customize this component's behavior?

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 the iframe element.

For example, if you want to add a title attribute to the iframe element, you can do so like such:

components.pyviews.pyapps.py
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
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
"},{"location":"reference/components/#django-css","title":"Django CSS","text":"

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
from 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
See Interface

Parameters

Name Type Description Default static_path str The path to the static file. This path is identical to what you would use on Django's {% static %} template tag. N/A key Key | None A key to uniquely identify this component which is unique amongst a component's immediate siblings None

Returns

Type Description Component A ReactPy component. Can I load static CSS using html.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:

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
How do I load external CSS?

django_css can only be used with local static files.

For external CSS, you should use html.link.

from 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
Why not load my CSS in <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 django_css component to defer loading your stylesheet until it is needed.

"},{"location":"reference/components/#django-js","title":"Django JS","text":"

Allows you to defer loading JavaScript until a component begins rendering. This JavaScript must be stored within Django's static files.

components.py
from 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
See Interface

Parameters

Name Type Description Default static_path str The path to the static file. This path is identical to what you would use on Django's {% static %} template tag. N/A key Key | None A key to uniquely identify this component which is unique amongst a component's immediate siblings None

Returns

Type Description Component A ReactPy component. Can I load static JavaScript using html.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:

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
How do I load external JS?

django_js can only be used with local static files.

For external JavaScript, you should use html.script.

from 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
Why not load my JS in <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 django_js component to defer loading your JavaScript until it is needed.

"},{"location":"reference/decorators/","title":"Decorators","text":""},{"location":"reference/decorators/#overview","title":"Overview","text":"

Decorator functions can be used within your components.py to help simplify development.

"},{"location":"reference/decorators/#user-passes-test","title":"User Passes Test","text":"

You can limit component access to users that pass a test function by using this decorator.

This only works with ReactPy components, and is inspired by Django's user_passes_test decorator.

components.py
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)\n@component\ndef my_component():\n    return html.div(\"I am logged in!\")\n
See Interface

Parameters

Name Type Description Default test_func Callable[[AbstractUser], bool] A function that accepts a User returns a boolean. N/A fallback Any | None The content to be rendered if the test fails. Typically is a ReactPy component or VDOM (reactpy.html snippet).

Returns

Type Description ComponentConstructor A ReactPy component constructor. How do I render a different component if the test fails?

You can use a component with the fallback argument, as seen below.

components.py
from 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
How do I render a simple reactpy.html snippet if the test fails?

You can use a reactpy.html snippet with the fallback argument, as seen below.

components.py
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
"},{"location":"reference/hooks/","title":"Hooks","text":""},{"location":"reference/hooks/#overview","title":"Overview","text":"

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 reactive-python/reactpy.

"},{"location":"reference/hooks/#database-hooks","title":"Database Hooks","text":""},{"location":"reference/hooks/#use-query","title":"Use Query","text":"

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 Django Model or QuerySet. This needs to be changed or disabled to execute other types of queries.

Query functions can be sync or async.

components.pymodels.py
from 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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
See Interface

Parameters

Name Type Description Default query Callable[FuncParams, Awaitable[Inferred]] | Callable[FuncParams, Inferred] A function that executes a query and returns some data. N/A kwargs dict[str, Any] | None Keyword arguments to passed into the query 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 query data before it is returned. The first argument of postprocessor function must be the query data. All proceeding arguments are optional postprocessor_kwargs. This postprocessor function must return the modified data. None postprocessor_kwargs dict[str, Any] | None Keyworded arguments passed into the postprocessor function. None

Returns

Type Description Query[Inferred] An object containing loading/error states, your data (if the query has successfully executed), and a refetch callable that can be used to re-run the query. How can I provide arguments to my query function?

kwargs can be provided to your query function via the kwargs=... parameter.

components.py
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
How can I customize this hook's behavior?

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.py
from 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 or ForeignKey fields is enabled within the django_query_postprocessor. This is needed to prevent SynchronousOnlyOperation exceptions when accessing these fields within your ReactPy components.

However, if you...

  1. Want to use this hook to defer IO intensive tasks to be computed in the background
  2. Want to to utilize use_query with a different ORM

... then you can either set a custom postprocessor, or disable all postprocessing behavior by modifying the postprocessor=... parameter. In the example below, we will set the postprocessor to None to disable postprocessing behavior.

components.py
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 postprocessor, you will need to create a function where the first must be the query data. All proceeding arguments are optional postprocessor_kwargs (see below). This postprocessor function must return the modified data.

components.py
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 or ForeignKey fields is enabled within the django_query_postprocessor. This is needed to prevent SynchronousOnlyOperation 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 postprocessor (located at reactpy_django.utils.django_query_postprocessor) via the postprocessor_kwargs=... parameter.

components.py
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 _set by default.

Can I make ORM calls without hooks?

Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a SynchronousOnlyOperation exception.

These 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.

Can I make a failed query try again?

Yes, use_mutation can be re-executed by calling reset() on your use_mutation instance.

For example, take a look at reset_event below.

components.pymodels.py
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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
Why does the example query function return TodoItem.objects.all()?

This design decision was based on Apollo's useQuery hook, but ultimately helps avoid Django's SynchronousOnlyOperation exceptions.

With the Model or QuerySet your function returns, this hook uses the default postprocessor to ensure that all deferred or lazy fields are executed.

"},{"location":"reference/hooks/#use-mutation","title":"Use Mutation","text":"

Modify data in the background, typically to create/update/delete data from the Django ORM.

Mutation functions can return False to manually prevent your refetch=... function from executing. All other returns are ignored.

Mutation functions can be sync or async.

components.pymodels.py
from 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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
See Interface

Parameters

Name Type Description Default mutation Callable[FuncParams, bool | None] | Callable[FuncParams, Awaitable[bool | None]] A callable that performs Django ORM create, update, or delete functionality. If this function returns False, then your refetch function will not be used. N/A thread_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 your use_query hook) or a sequence of query functions that need a refetch if the mutation succeeds. This is useful for refreshing data after a mutation has been performed. None

Returns

Type Description Mutation[FuncParams] An object containing loading/error states, and a reset callable that will set loading/error states to defaults. This object can be called to run the query. How can I provide arguments to my mutation function?

*args and **kwargs can be provided to your mutation function via mutation(...) parameters.

components.py
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
How can I customize this hook's behavior?

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
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
Can I make ORM calls without hooks?

Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a SynchronousOnlyOperation exception.

These 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.

Can I make a failed mutation try again?

Yes, use_mutation can be re-executed by calling reset() on your use_mutation instance.

For example, take a look at reset_event below.

components.pymodels.py
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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
Can use_mutation trigger a refetch of use_query?

Yes, use_mutation can queue a refetch of a use_query via the refetch=... argument.

The example below is a merge of the use_query and use_mutation examples above with the addition of a use_mutation(refetch=...) argument.

Please note that refetch will cause all use_query hooks that use get_items in the current component tree will be refetched.

components.pymodels.py
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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
"},{"location":"reference/hooks/#use-user-data","title":"Use User Data","text":"

Store or retrieve a dict containing user data specific to the connection's User.

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 REACTPY_DATABASE.

components.py
from 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
See Interface

Parameters

Name Type Description Default default_data None | dict[str, Callable[[], Any] | Callable[[], Awaitable[Any]] | Any] A dictionary containing {key: default_value} pairs. For computationally intensive defaults, your default_value can be sync or async functions that return the value to set. None save_default_data bool If True, default_data values will automatically be stored within the database if they do not exist. False

Returns

Type Description UserData A NamedTuple containing a Query and Mutation objects used to access/modify user data. Read the use_query and use_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 {key: default_value} pairs. For computationally intensive defaults, your default_value can be sync or async functions that return the value to set.

components.py
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
"},{"location":"reference/hooks/#communication-hooks","title":"Communication Hooks","text":""},{"location":"reference/hooks/#use-channel-layer","title":"Use Channel Layer","text":"

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
from 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
See Interface

Parameters

Name Type Description Default name str | None The name of the channel to subscribe to. If you define a group_name, you can keep name 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 If True, the channel will automatically be added to the group when the component mounts. True group_discard bool If True, the channel will automatically be removed from the group when the component dismounts. True receiver AsyncMessageReceiver | None An async function that receives a message: 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 in settings.py:CHANNEL_LAYERS. 'default'

Returns

Type Description AsyncMessageSender An async callable that can send a message: dict. Extra Django configuration required

In 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:

  1. Install redis on your machine.

  2. Run the following command to install channels-redis in your Python environment.

    pip install channels-redis\n
  3. Configure your settings.py to use RedisChannelLayer 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
How do I broadcast a message to multiple components?

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 channel name while using groups, ReactPy will automatically generate a unique channel name for you.

In the example below, all messages sent by the sender component will be received by all receiver components that exist (across every active client browser).

components.py
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
How do I signal a re-render from something that isn't a component?

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 the get_channel_layer().send(...) to send the signal.

In the example below, the sender will signal every time ExampleModel is saved. Then, when the receiver gets this signal, it explicitly calls set_message(...) to trigger a re-render.

signals.pycomponents.py
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
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
"},{"location":"reference/hooks/#connection-hooks","title":"Connection Hooks","text":""},{"location":"reference/hooks/#use-connection","title":"Use Connection","text":"

Returns the active connection, which is either a Django WebSocket or a HTTP Request.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description Connection An object that contains a carrier (WebSocket or HttpRequest), scope, and location."},{"location":"reference/hooks/#use-scope","title":"Use Scope","text":"

Shortcut that returns the WebSocket or HTTP connection's scope.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description MutableMapping[str, Any] The connection's scope."},{"location":"reference/hooks/#use-location","title":"Use Location","text":"

Shortcut that returns the browser's current Location.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description Location An object containing the current URL's pathname and search 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 http://example.com.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description str | 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 a randomly generated uuid4. It is notable to mention that it is persistent across the current connection. The uuid is reset when the page is refreshed.

This is useful when used in combination with use_channel_layer to send messages to a specific component instance, and/or retain a backlog of messages in case that component is disconnected via use_channel_layer( ... , group_discard=False).

components.py
from 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
See Interface

Parameters

None

Returns

Type Description str A string containing the root component's id."},{"location":"reference/hooks/#use-user","title":"Use User","text":"

Shortcut that returns the WebSocket or HTTP connection's User.

components.py
from 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
See Interface

Parameters

None

Returns

Type Description AbstractUser A Django User, which can also be an AnonymousUser."},{"location":"reference/html/","title":"HTML","text":""},{"location":"reference/html/#overview","title":"Overview","text":"

We supply some HTML elements can be used to help simplify development.

"},{"location":"reference/html/#pyscript","title":"PyScript","text":"

PyScript code block. The text content of this tag are executed within the PyScript interpreter. This can be used as an alternative to the reactpy.html.script.

This is a primitive HTML tag that is leveraged by reactpy_django.components.pyscript_component.

The pyscript tag functions identically to HTML tags contained within reactpy.html.

components.pymy_template.html
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
{% 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
You must call pyscript_setup in your Django template before using this tag!

This requires using of the {% pyscript_setup %} template tag to initialize PyScript on the client.

my_template.html
{% load reactpy %}\n\n<head>\n    <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
"},{"location":"reference/management-commands/","title":"Management Commands","text":""},{"location":"reference/management-commands/#overview","title":"Overview","text":"

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 expired ReactPy data from the database and/or cache.

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

python manage.py clean_reactpy\n
See Interface

Type python manage.py clean_reactpy --help to see the available options.

"},{"location":"reference/router/","title":"URL Router","text":""},{"location":"reference/router/#overview","title":"Overview","text":"

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 reactive-python/reactpy-router.

"},{"location":"reference/router/#django-router","title":"Django Router","text":"

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 will always handle the initial load of the webpage.

You can duplicate all your URL patterns within both Django and ReactPy, but it's easiest to use a wildcard .* within Django's urlpatterns and let ReactPy handle the rest. For example...

urlpatterns = [\n    re_path(r\"^.*$\", my_reactpy_router_view),\n]\n
components.py
from 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
See Interface

Parameters

Name Type Description Default *routes Route An object from reactpy-router containing a path, element, and child *routes. N/A

Returns

Type Description VdomDict | None The matched component/path after it has been fully rendered. How is this different from reactpy_router.simple.router?

This component utilizes reactpy-router under the hood, but provides a more Django-like URL routing syntax.

"},{"location":"reference/settings/","title":"Settings","text":""},{"location":"reference/settings/#overview","title":"Overview","text":"

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 REACTPY_DEFAULT_QUERY_POSTPROCESSOR to None to disable the default postprocessor.

"},{"location":"reference/settings/#reactpy_auth_backend","title":"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:

  1. You are using settings.py:REACTPY_AUTO_RELOGIN=True and...
  2. You are using AuthMiddlewareStack and...
  3. You are using Django's AUTHENTICATION_BACKENDS setting and...
  4. Your Django user model does not define a backend attribute.
"},{"location":"reference/settings/#reactpy_auto_relogin","title":"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 last_login timestamps and refresh the Django login session.

"},{"location":"reference/settings/#performance-settings","title":"Performance Settings","text":""},{"location":"reference/settings/#reactpy_database","title":"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
DATABASE_ROUTERS = [\"reactpy_django.database.Router\", ...]\n
"},{"location":"reference/settings/#reactpy_cache","title":"REACTPY_CACHE","text":"

Default: \"default\"

Example Value(s): \"my-reactpy-cache\"

Cache used by ReactPy, typically for caching disk operations.

We recommend using redis, memcache, or local-memory caching.

"},{"location":"reference/settings/#reactpy_backhaul_thread","title":"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 and uvicorn.

This setting is incompatible with daphne.

"},{"location":"reference/settings/#reactpy_default_hosts","title":"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 host argument in your template tag to manually override this default.

"},{"location":"reference/settings/#reactpy_prerender","title":"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:

  1. Only the component's first paint is pre-rendered.
  2. All connection hooks will provide HTTP variants.
  3. The component will be non-interactive until a WebSocket connection is formed.
  4. The component is re-rendered once a WebSocket connection is formed.

You can use the prerender argument in your template tag to manually override this default.

"},{"location":"reference/settings/#stability-settings","title":"Stability Settings","text":""},{"location":"reference/settings/#reactpy_reconnect_interval","title":"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 1.

"},{"location":"reference/settings/#reactpy_reconnect_max_interval","title":"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 REACTPY_RECONNECT_BACKOFF_MULTIPLIER can increase the time between reconnection attempts.

"},{"location":"reference/settings/#reactpy_reconnect_max_retries","title":"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 0 to not store any session data.

"},{"location":"reference/settings/#auto-clean-settings","title":"Auto-Clean Settings","text":""},{"location":"reference/settings/#reactpy_clean_interval","title":"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 None to disable automatic clean up operations.

"},{"location":"reference/settings/#reactpy_clean_sessions","title":"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 User delete operation.

"},{"location":"reference/template-tag/","title":"Template Tag","text":""},{"location":"reference/template-tag/#overview","title":"Overview","text":"

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 server-side ReactPy components onto your page.

Each component loaded via this template tag will receive a dedicated WebSocket connection to the server.

my_template.html
{% 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
See Interface

Parameters

Name Type Description Default dotted_path str The dotted path to the component to render. N/A *args Any The positional arguments to provide to the component. N/A class 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. Using key 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, this offline 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 path

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 register_component function to manually register your components.

Can I use multiple components on one page?

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.my_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 <body> tag.

Can I use positional arguments instead of keyword arguments?

You can use any combination of *args/**kwargs in your template tag.

my_template.htmlcomponents.py
{% component \"example_project.my_app.components.frog_greeter\" 123 \"Mr. Froggles\" species=\"Grey Treefrog\" %}\n
from reactpy import component\n\n\n@component\ndef frog_greeter(number, name, species=\"\"):\n    return f\"Hello #{number}, {name} the {species}!\"\n
Can I render components on a different server (distributed computing)?

Yes! This is most commonly done through settings.py:REACTPY_HOSTS. However, you can use the host keyword to render components on a specific ASGI server.

my_template.html
...\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:

  1. If your host address are completely separate ( origin1.com != origin2.com ) you will need to configure CORS headers on your main application during deployment.
  2. You will not need to register ReactPy WebSocket or HTTP paths on any applications that do not perform any component rendering.
  3. Your component will only be able to access your template tag's *args/**kwargs if your applications share a common database.
How do I pre-render components for SEO compatibility?

This is most commonly done through settings.py:REACTPY_PRERENDER. However, you can use the prerender keyword to pre-render a specific component.

my_template.html
...\n{% component \"example_project.my_app.components.do_something\" prerender=\"true\" %}\n...\n
How do I display something when the client disconnects?

You can use the offline keyword to display a specific component when the client disconnects from the server.

my_template.html
...\n{% component \"example_project.my_app.components.do_something\" offline=\"example_project.my_app.components.offline\" %}\n...\n

Note: The offline component will be non-interactive (hooks won't operate).

"},{"location":"reference/template-tag/#pyscript-component","title":"PyScript Component","text":"

This template tag can be used to insert any number of client-side ReactPy components onto your page.

By default, the only available dependencies are the Python standard library, pyscript, pyodide, reactpy core.

The entire file path provided is loaded directly into the browser, and must have a def root() component to act as the entry point.

Pitfall

Similar to JavaScript, your provided Python file is loaded directly into the client (web browser) as raw text to run using the PyScript interpreter. Be cautious about what you include in your Python file.

As a result being client-sided, Python packages within your local environment (such as those installed via pip install ...) are not accessible within PyScript components.

my_template.htmlhello_world.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/hello_world.py\" %}\n</body>\n\n</html>\n
from reactpy import component, html\n\n\n@component\ndef root():\n    return html.div(\"Hello, World!\")\n
See Interface

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/A initial str | VdomDict | ComponentType The initial HTML that is displayed prior to the PyScript component loads. This can either be a string containing raw HTML, a reactpy.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 several options available to execute JavaScript, including...

  • Pyodide's js module
  • Pyscript's foreign function interface
  • Pyscript's JavaScript modules.

Pyodide JS Module

The Pyodide js 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, you will need to be mindful of JavaScript load order if using async or deferred loading!

root.py
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

PyScript FFI

...

PyScript JS Modules

Assuming you have a local bundle stored within your project's static files, you can import JavaScript modules in a fashion similar to import {moment} from 'static/moment.js'. You will first need to configure your {% pyscript_setup %} block to make the moment.js module available to PyScript. Then, this module can be accessed within pyscript.js_modules.*.

root.pymy_template.html
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
{% 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
Does my entire component need to be contained in one file?

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
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
How do I display something while the component is loading?

You can configure the initial keyword to display HTML while your PyScript component is loading.

The value for initial is most commonly be a string containing raw HTML.

my_template.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 reactpy.html snippet or a non-interactive @component via template context.

my_template.htmlviews.py
<body>\n{% pyscript_component \"./example_project/my_app/components/root.py\" initial=my_initial_object %}\n</body>\n
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
Can I use a different name for my root component?

Yes, you can use the root keyword to specify a different name for your root function.

my_template.htmlmain.py
<body>\n{% pyscript_component \"./example_project/my_app/components/main.py\" root=\"main\" %}\n</body>\n
from reactpy import component, html\n\n\n@component\ndef main():\n    return html.div(\"Hello, World!\")\n
"},{"location":"reference/template-tag/#pyscript-setup","title":"PyScript Setup","text":"

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
{% load reactpy %}\n\n<head>\n    <title>ReactPy</title>\n{% pyscript_setup %}\n</head>\n
See Interface

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/A extra_js str | dict A JSON string or Python dictionary containing a vanilla JavaScript module URL and the name: str to access it within pyscript.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
<head>\n    <title>ReactPy</title>\n{% pyscript_setup \"dill==0.3.5\" \"markdown<=3.6.0\" \"nest_asyncio\" \"titlecase\" %}\n</head>\n
How do I install additional Javascript dependencies?

You can use the extra_js keyword to load additional JavaScript modules into your PyScript environment.

my_template.htmlviews.py
{% 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 extra_js is most commonly a Python dictionary, but JSON strings are also supported.

my_template.html
{% 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
How do I modify the pyscript default configuration?

You can modify the default PyScript configuration by providing a value to the config keyword.

my_template.html
<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
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
"},{"location":"reference/utils/","title":"Utilities","text":""},{"location":"reference/utils/#overview","title":"Overview","text":"

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 Django view as a ReactPy iframe.

It is mandatory to use this function alongside view_to_iframe.

apps.py
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
See Interface

Parameters

Name Type Description Default view Callable | View | str The view to register. Can be a function or class based view, or a dotted path to a view. N/A

Returns

None

Only use this within AppConfig.ready()

You should always call register_iframe within a Django AppConfig.ready() method. This ensures you will retain multiprocessing compatibility, such as with ASGI web server workers.

"},{"location":"reference/utils/#register-component","title":"Register Component","text":"

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
from 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
See Interface

Parameters

Name Type Description Default component ComponentConstructor | str The component to register. Can be a component function or dotted path to a component. N/A

Returns

None

Only use this within MyAppConfig.ready()

You should always call register_component within a Django MyAppConfig.ready() method. This ensures you will retain multiprocessing compatibility, such as with ASGI web server workers.

Do I need to use this?

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 host to a dedicated Django rendering application that doesn't have templates.

"},{"location":"reference/utils/#django-query-postprocessor","title":"Django Query Postprocessor","text":"

This is the default postprocessor for the use_query hook.

Since ReactPy is rendered within an asyncio loop, this postprocessor is exists to prevent Django's SynchronousOnlyException by recursively prefetching fields within Django's ORM. Note that this effectively eliminates Django's lazy execution behavior.

components.pymodels.py
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
from django.db.models import CharField, Model\n\n\nclass TodoItem(Model):\n    text: CharField = CharField(max_length=255)\n
See Interface

Parameters

Name Type Description Default data QuerySet | Model The Model or QuerySet to recursively fetch fields from. N/A many_to_many bool Whether or not to recursively fetch ManyToManyField relationships. True many_to_one bool Whether or not to recursively fetch ForeignKey relationships. True

Returns

Type Description QuerySet | Model The Model or QuerySet with all fields fetched."}]} \ No newline at end of file