Skip to content

Commit 9c28f97

Browse files
committed
First cut at docs
1 parent aee08da commit 9c28f97

9 files changed

+175
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{% load django_bootstrap5 %}
2+
3+
<!-- Note: CSS/JS is loaded here only for demonstration purposes.
4+
You should load this CSS/JS in your HTML <head> instead. -->
5+
{% bootstrap_css %}
6+
{% bootstrap_javascript %}
7+
8+
<!-- The actual form that is rendered by ReactPy -->
9+
{% bootstrap_form form %}
10+
{% bootstrap_button button_type="submit" content="OK" %}
11+
{% bootstrap_button button_type="reset" content="Reset" %}

docs/examples/python/django_form.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from reactpy import component, html
2+
3+
from example.forms import MyForm
4+
from reactpy_django.components import django_form
5+
6+
7+
@component
8+
def basic_form():
9+
children = [html.input({"type": "submit"})]
10+
return django_form(MyForm, bottom_children=children)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from reactpy import component
2+
3+
from example.forms import MyForm
4+
from reactpy_django.components import django_form
5+
6+
7+
@component
8+
def basic_form():
9+
return django_form(MyForm, form_template="bootstrap_form.html")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django import forms
2+
3+
4+
class MyForm(forms.Form):
5+
username = forms.CharField(label="Username")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from reactpy import component, hooks, html
2+
from reactpy_router import navigate
3+
4+
from example.forms import MyForm
5+
from reactpy_django.components import django_form
6+
from reactpy_django.types import FormEventData
7+
8+
9+
@component
10+
def basic_form():
11+
success, set_success = hooks.use_state(False)
12+
13+
def on_success(event: FormEventData):
14+
set_success(True)
15+
16+
if not success:
17+
children = [html.input({"type": "submit"})]
18+
return django_form(MyForm, on_success=on_success, bottom_children=children)
19+
20+
return navigate("/homepage")

docs/examples/python/example/forms.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from django import forms
2+
3+
4+
class MyForm(forms.Form): ...

docs/src/dictionary.txt

+1
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ linter
4848
linters
4949
linting
5050
formatters
51+
bootstrap_form

docs/src/reference/components.md

+101-4
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject.
156156

157157
??? info "Existing limitations"
158158

159-
There are currently several limitations of using `#!python view_to_component` that may be resolved in a future version.
159+
There are currently several limitations of using `#!python view_to_component` that will be [resolved in a future version](https://github.com/reactive-python/reactpy-django/issues/269).
160160

161161
- Requires manual intervention to change HTTP methods to anything other than `GET`.
162162
- ReactPy events cannot conveniently be attached to converted view HTML.
@@ -292,12 +292,12 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject.
292292

293293
??? info "Existing limitations"
294294

295-
There are currently several limitations of using `#!python view_to_iframe` that may be resolved in a future version.
295+
There are currently several limitations of using `#!python view_to_iframe` which may be [resolved in a future version](https://github.com/reactive-python/reactpy-django/issues/268).
296296

297297
- No built-in method of signalling events back to the parent component.
298-
- All provided `#!python *args` and `#!python *kwargs` must be serializable values, since they are encoded into the URL.
298+
- All provided `#!python args` and `#!python kwargs` must be serializable values, since they are encoded into the URL.
299299
- The `#!python iframe` will always load **after** the parent component.
300-
- CSS styling for `#!python iframe` elements tends to be awkward/difficult.
300+
- CSS styling for `#!python iframe` elements tends to be awkward.
301301

302302
??? question "How do I use this for Class Based Views?"
303303

@@ -381,6 +381,103 @@ Compatible with sync or async [Function Based Views](https://docs.djangoproject.
381381

382382
---
383383

384+
## Django Form
385+
386+
Automatically convert a Django form into a ReactPy component.
387+
388+
Compatible with both [standard Django forms](https://docs.djangoproject.com/en/stable/topics/forms/#building-a-form) and [ModelForms](https://docs.djangoproject.com/en/stable/topics/forms/modelforms/).
389+
390+
=== "components.py"
391+
392+
```python
393+
{% include "../../examples/python/django_form.py" %}
394+
```
395+
396+
=== "forms.py"
397+
398+
```python
399+
{% include "../../examples/python/django_form_class.py" %}
400+
```
401+
402+
??? example "See Interface"
403+
404+
<font size="4">**Parameters**</font>
405+
406+
| Name | Type | Description | Default |
407+
| --- | --- | --- | --- |
408+
| `#!python form` | `#!python type[Form | ModelForm]` | The form instance to convert. | N/A |
409+
| `#!python on_success` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when the form is successfully submitted. | `#!python None` |
410+
| `#!python on_error` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when the form submission fails. | `#!python None` |
411+
| `#!python on_receive_data` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called before newly submitted form data is rendered. | `#!python None` |
412+
| `#!python on_change` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when the form is changed. | `#!python None` |
413+
| `#!python auto_save` | `#!python bool` | If `#!python True`, the form will automatically call `#!python save` on successful submission of a `#!python ModelForm`. This has no effect on regular `#!python Form` instances. | `#!python False` |
414+
| `#!python extra_props` | `#!python dict[str, Any] | None` | Additional properties to add to the `#!html <form>` element. | `#!python None` |
415+
| `#!python extra_transforms` | `#!python Sequence[Callable[[VdomDict], Any]] | None` | A list of functions that transforms the newly generated VDOM. The functions will be repeatedly called on each VDOM node. | `#!python None` |
416+
| `#!python form_template` | `#!python str | None` | The template to use for the form. If `#!python None`, Django's default template is used. | `#!python None` |
417+
| `#!python top_children` | `#!python Sequence[Any]` | Additional elements to add to the top of the form. | `#!python tuple` |
418+
| `#!python bottom_children` | `#!python Sequence[Any]` | Additional elements to add to the bottom of the form. | `#!python tuple` |
419+
| `#!python key` | `#!python Key | None` | A key to uniquely identify this component which is unique amongst a component's immediate siblings. | `#!python None` |
420+
421+
<font size="4">**Returns**</font>
422+
423+
| Type | Description |
424+
| --- | --- |
425+
| `#!python Component` | A ReactPy component. |
426+
427+
??? info "Existing limitations"
428+
429+
The following fields are currently incompatible with `#!python django_form`: `#!python FileField`, `#!python ImageField`, `#!python SplitDateTimeField`, and `#!python MultiValueField`.
430+
431+
Compatibility for these fields will be [added in a future version](https://github.com/reactive-python/reactpy-django/issues/270).
432+
433+
??? question "How do I style these forms with Bootstrap?"
434+
435+
You can style these forms by using a form styling library. In the example below, it is assumed that you have already installed [`django-bootstrap5`](https://pypi.org/project/django-bootstrap5/).
436+
437+
After installing a form styling library, you can then provide ReactPy a custom `#!python form_template` parameter. This parameter allows you to specify a custom HTML template to use to render this the form.
438+
439+
Note that you can also set a global default for `form_template` by using [`settings.py:REACTPY_DEFAULT_FORM_TEMPLATE`](./settings.md#reactpy_default_form_template).
440+
441+
=== "components.py"
442+
443+
```python
444+
{% include "../../examples/python/django_form_bootstrap.py" %}
445+
```
446+
447+
=== "forms.py"
448+
449+
```python
450+
{% include "../../examples/python/django_form_class.py" %}
451+
```
452+
453+
=== "bootstrap_form.html"
454+
455+
```jinja
456+
{% include "../../examples/html/django_form_bootstrap.html" %}
457+
```
458+
459+
??? question "How do I handle form success/errors?"
460+
461+
You can react to form state by providing a callback function to any of the following parameters: `#!python on_success`, `#!python on_error`, `#!python on_receive_data`, and `#!python on_change`.
462+
463+
These functions will be called when the form is submitted.
464+
465+
In the example below, we will use the `#!python on_success` parameter to change the URL upon successful submission.
466+
467+
=== "components.py"
468+
469+
```python
470+
{% include "../../examples/python/django_form_on_success.py" %}
471+
```
472+
473+
=== "forms.py"
474+
475+
```python
476+
{% include "../../examples/python/django_form_class.py" %}
477+
```
478+
479+
---
480+
384481
## Django CSS
385482

386483
Allows you to defer loading a CSS stylesheet until a component begins rendering. This stylesheet must be stored within [Django's static files](https://docs.djangoproject.com/en/stable/howto/static-files/).

docs/src/reference/settings.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ The prefix used for all ReactPy WebSocket and HTTP URLs.
3434

3535
**Example Value(s):** `#!python "example_project.postprocessor"`, `#!python None`
3636

37-
Dotted path to the default `#!python reactpy_django.hooks.use_query` postprocessor function.
37+
Dotted path to the default postprocessor function used by the [`use_query`](./hooks.md#use-query) hook.
3838

3939
Postprocessor functions can be async or sync. Here is an example of a sync postprocessor function:
4040

@@ -48,6 +48,18 @@ Set `#!python REACTPY_DEFAULT_QUERY_POSTPROCESSOR` to `#!python None` to disable
4848

4949
---
5050

51+
### `#!python REACTPY_DEFAULT_FORM_TEMPLATE`
52+
53+
**Default:** `#!python None`
54+
55+
**Example Value(s):** `#!python "my_templates/bootstrap_form.html"`
56+
57+
File path to the default form template used by the [`django_form`](./components.md#django-form) component.
58+
59+
This file path must be valid to Django's [template finder](https://docs.djangoproject.com/en/stable/topics/templates/#support-for-template-engines).
60+
61+
---
62+
5163
### `#!python REACTPY_AUTH_BACKEND`
5264

5365
**Default:** `#!python "django.contrib.auth.backends.ModelBackend"`
@@ -131,7 +143,7 @@ This setting is incompatible with [`daphne`](https://github.com/django/daphne).
131143

132144
Configures whether to use an async ReactPy rendering queue. When enabled, large renders will no longer block smaller renders from taking place. Additionally, prevents the rendering queue from being blocked on waiting for async effects to startup/shutdown (which is typically a relatively slow operation).
133145

134-
This setting is currently experimental, and currently no effort is made to de-duplicate renders. For example, if parent and child components are scheduled to render at the same time, both renders will take place even though a single render of the parent component would have been sufficient.
146+
This setting is currently in early release, and currently no effort is made to de-duplicate renders. For example, if parent and child components are scheduled to render at the same time, both renders will take place even though a single render of the parent component would have been sufficient.
135147

136148
---
137149

0 commit comments

Comments
 (0)