Skip to content

Commit 101f768

Browse files
committed
Docs readability enhancements
1 parent 9973403 commit 101f768

File tree

10 files changed

+118
-77
lines changed

10 files changed

+118
-77
lines changed

docs/includes/orm.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a `#!python SynchronousOnlyOperation` exception.
44

5-
These `#!python SynchronousOnlyOperation` exceptions may be resolved in a future version of Django containing an asynchronous ORM. However, it is best practice to always perform ORM calls in the background via hooks.
5+
These `#!python 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.
66

77
<!--orm-excp-end-->
88

99
<!--orm-fetch-start-->
1010

11-
By default, automatic recursive fetching of `#!python ManyToMany` or `#!python ForeignKey` fields is enabled within the default `#!python QueryOptions.postprocessor`. This is needed to prevent `#!python SynchronousOnlyOperation` exceptions when accessing these fields within your ReactPy components.
11+
By default, automatic recursive fetching of `#!python ManyToMany` or `#!python ForeignKey` fields is enabled within the `DjangoQueryPostprocessor`. This is needed to prevent `#!python SynchronousOnlyOperation` exceptions when accessing these fields within your ReactPy components.
1212

1313
<!--orm-fetch-end-->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from reactpy import component, html
2+
from reactpy_django.hooks import use_mutation
3+
from reactpy_django.types import MutationOptions
4+
5+
6+
def execute_thread_safe_mutation():
7+
"""This is an example mutation function that does some thread-safe operation."""
8+
pass
9+
10+
11+
@component
12+
def my_component():
13+
item_mutation = use_mutation(
14+
MutationOptions(thread_sensitive=False),
15+
execute_thread_safe_mutation,
16+
)
17+
18+
def submit_event(event):
19+
if event["key"] == "Enter":
20+
item_mutation.execute(text=event["target"]["value"])
21+
22+
if item_mutation.loading or item_mutation.error:
23+
mutation_status = html.h2("Doing something...")
24+
elif item_mutation.error:
25+
mutation_status = html.h2("Error!")
26+
else:
27+
mutation_status = html.h2("Done.")
28+
29+
return html.div(
30+
html.input({"type": "text", "onKeyDown": submit_event}),
31+
mutation_status,
32+
)

docs/python/use-query-async.py

-22
This file was deleted.

docs/src/reference/components.md

+12-16
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ Allows you to defer loading a CSS stylesheet until a component begins rendering.
177177

178178
| Name | Type | Description | Default |
179179
| --- | --- | --- | --- |
180-
| `#!python static_path` | `#!python str` | The path to the static file. This path is identical to what you would use on a `static` template tag. | N/A |
180+
| `#!python static_path` | `#!python str` | The path to the static file. This path is identical to what you would use on Django's `#!jinja {% static %}` template tag. | N/A |
181181
| `#!python key` | `#!python Key | None` | A key to uniquely identify this component which is unique amongst a component's immediate siblings | `#!python None` |
182182

183183
<font size="4">**Returns**</font>
@@ -186,10 +186,6 @@ Allows you to defer loading a CSS stylesheet until a component begins rendering.
186186
| --- | --- |
187187
| `#!python Component` | A ReactPy component. |
188188

189-
??? question "Should I put `#!python django_css` at the top of my HTML?"
190-
191-
Yes, if the stylesheet contains styling for your component.
192-
193189
??? question "Can I load static CSS using `#!python html.link` instead?"
194190

195191
While you can load stylesheets with `#!python 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.
@@ -204,22 +200,26 @@ Allows you to defer loading a CSS stylesheet until a component begins rendering.
204200

205201
`#!python django_css` can only be used with local static files.
206202

207-
For external CSS, substitute `#!python django_css` with `#!python html.link`.
203+
For external CSS, you should use `#!python html.link`.
208204

209205
```python
210206
{% include "../../python/django-css-external-link.py" %}
211207
```
212208

213209
??? question "Why not load my CSS in `#!html <head>`?"
214210

215-
Traditionally, stylesheets are loaded in your `#!html <head>` using the `#!jinja {% load static %}` template tag.
211+
Traditionally, stylesheets are loaded in your `#!html <head>` using Django's `#!jinja {% static %}` template tag.
216212

217-
To help improve webpage load times, you can use the `#!python django_css` component to defer loading your stylesheet until it is needed.
213+
However, to help improve webpage load times you can use this `#!python django_css` component to defer loading your stylesheet until it is needed.
218214

219215
## Django JS
220216

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

219+
!!! warning "Pitfall"
220+
221+
Be mindful of load order! If your JavaScript relies on the component existing on the page, you must place `django_js` at the **bottom** of your component.
222+
223223
=== "components.py"
224224

225225
```python
@@ -232,7 +232,7 @@ Allows you to defer loading JavaScript until a component begins rendering. This
232232

233233
| Name | Type | Description | Default |
234234
| --- | --- | --- | --- |
235-
| `#!python static_path` | `#!python str` | The path to the static file. This path is identical to what you would use on a `static` template tag. | N/A |
235+
| `#!python static_path` | `#!python str` | The path to the static file. This path is identical to what you would use on Django's `#!jinja {% static %}` template tag. | N/A |
236236
| `#!python key` | `#!python Key | None` | A key to uniquely identify this component which is unique amongst a component's immediate siblings | `#!python None` |
237237

238238
<font size="4">**Returns**</font>
@@ -241,10 +241,6 @@ Allows you to defer loading JavaScript until a component begins rendering. This
241241
| --- | --- |
242242
| `#!python Component` | A ReactPy component. |
243243

244-
??? question "Should I put `#!python django_js` at the bottom of my HTML?"
245-
246-
Yes, if your scripts are reliant on the contents of the component.
247-
248244
??? question "Can I load static JavaScript using `#!python html.script` instead?"
249245

250246
While you can load JavaScript with `#!python 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.
@@ -259,14 +255,14 @@ Allows you to defer loading JavaScript until a component begins rendering. This
259255

260256
`#!python django_js` can only be used with local static files.
261257

262-
For external JavaScript, substitute `#!python django_js` with `#!python html.script`.
258+
For external JavaScript, you should use `#!python html.script`.
263259

264260
```python
265261
{% include "../../python/django-js-remote-script.py" %}
266262
```
267263

268264
??? question "Why not load my JS in `#!html <head>`?"
269265

270-
Traditionally, JavaScript is loaded in your `#!html <head>` using the `#!jinja {% load static %}` template tag.
266+
Traditionally, JavaScript is loaded in your `#!html <head>` using Django's `#!jinja {% static %}` template tag.
271267

272-
To help improve webpage load times, you can use the `#!python django_js` component to defer loading your JavaScript until it is needed.
268+
However, to help improve webpage load times you can use this `#!python django_js` component to defer loading your JavaScript until it is needed.

docs/src/reference/decorators.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Decorator functions can be used within your `components.py` to help simplify dev
1010

1111
## Auth Required
1212

13-
You can limit access to a component to users with a specific `#!python auth_attribute` by using this decorator (with or without parentheses).
13+
You can limit component access to users with a specific `#!python auth_attribute` by using this decorator (with or without parentheses).
1414

1515
By default, this decorator checks if the user is logged in and not deactivated (`#!python is_active`).
1616

docs/src/reference/hooks.md

+64-32
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ Prefabricated hooks can be used within your `components.py` to help simplify dev
1616

1717
## Use Query
1818

19-
This hook is used [read](https://www.sumologic.com/glossary/crud/) data from the Django ORM.
19+
This hook is used [read](https://www.sumologic.com/glossary/crud/) data, typically from the Django ORM.
2020

21-
The query function you provide must return either a `#!python Model` or `#!python QuerySet`.
21+
The [default postprocessor](../reference/utils.md#django-query-postprocessor) expects your query function to return either a Django `#!python Model` or `#!python QuerySet`. The postprocessor needs to be changed to perform other types of queries. Query functions can be sync or async.
2222

2323
=== "components.py"
2424

@@ -59,13 +59,13 @@ The query function you provide must return either a `#!python Model` or `#!pytho
5959
{% include "../../python/use-query-args.py" %}
6060
```
6161

62-
??? question "Why does `#!python get_items` in the example return `#!python TodoItem.objects.all()`?"
62+
??? question "How can I customize this hook's behavior?"
6363

64-
This was a technical design decision to based on [Apollo's `#!javascript useQuery` hook](https://www.apollographql.com/docs/react/data/queries/), but ultimately helps avoid Django's `#!python SynchronousOnlyOperation` exceptions.
64+
This hook accepts a `#!python options = ...` parameter that can be used to customize its behavior. You can provide a `#!python reactpy_django.types.QueryOptions` object to this parameter to customize the hook's behavior.
6565

66-
The `#!python use_query` hook ensures the provided `#!python Model` or `#!python QuerySet` executes all [deferred](https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_deferred_fields)/[lazy queries](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy) safely prior to reaching your components.
66+
Below are the settings that can be modified via `#!python QueryOptions`.
6767

68-
??? question "How can I use `#!python QueryOptions` to customize fetching behavior?"
68+
---
6969

7070
<font size="4">**`#!python thread_sensitive`**</font>
7171

@@ -128,27 +128,39 @@ The query function you provide must return either a `#!python Model` or `#!pytho
128128

129129
_Note: In Django's ORM design, the field name to access foreign keys is [postfixed with `_set`](https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_one/) by default._
130130

131-
??? question "Can I define async query functions?"
131+
??? question "Can I make ORM calls without hooks?"
132+
133+
{% include-markdown "../../includes/orm.md" start="<!--orm-excp-start-->" end="<!--orm-excp-end-->" %}
132134

133-
Async functions are supported by `#!python use_query`. You can use them in the same way as a sync query function.
135+
??? question "Can I make a failed query try again?"
134136

135-
However, be mindful of Django async ORM restrictions.
137+
Yes, a `#!python use_mutation` can be re-performed by calling `#!python reset()` on your `#!python use_mutation` instance.
138+
139+
For example, take a look at `#!python reset_event` below.
136140

137141
=== "components.py"
138142

139143
```python
140-
{% include "../../python/use-query-async.py" %}
144+
{% include "../../python/use-mutation-reset.py" %}
141145
```
142146

143-
??? question "Can I make ORM calls without hooks?"
147+
=== "models.py"
144148

145-
{% include-markdown "../../includes/orm.md" start="<!--orm-excp-start-->" end="<!--orm-excp-end-->" %}
149+
```python
150+
{% include "../../python/example/models.py" %}
151+
```
152+
153+
??? question "Why does the example query function return `#!python TodoItem.objects.all()`?"
154+
155+
This design decision was based on [Apollo's `#!javascript useQuery` hook](https://www.apollographql.com/docs/react/data/queries/), but ultimately helps avoid Django's `#!python SynchronousOnlyOperation` exceptions.
156+
157+
With the `#!python Model` or `#!python QuerySet` your function returns, this hook uses the [default postprocessor](../reference/utils.md#django-query-postprocessor) to ensure that all [deferred](https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_deferred_fields) or [lazy](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy) fields are executed.
146158

147159
## Use Mutation
148160

149-
This hook is used to [create, update, or delete](https://www.sumologic.com/glossary/crud/) Django ORM objects.
161+
This hook is used to [create, update, or delete](https://www.sumologic.com/glossary/crud/) data, typically from the Django ORM.
150162

151-
The mutation function you provide should have no return value.
163+
The mutation function you provide should have no return value. Mutation functions can be sync or async.
152164

153165
=== "components.py"
154166

@@ -187,27 +199,31 @@ The mutation function you provide should have no return value.
187199
{% include "../../python/use-mutation-args-kwargs.py" %}
188200
```
189201

190-
??? question "Can `#!python use_mutation` trigger a refetch of `#!python use_query`?"
202+
??? question "How can I customize this hook's behavior?"
191203

192-
Yes, `#!python use_mutation` can queue a refetch of a `#!python use_query` via the `#!python refetch=...` argument.
204+
This hook accepts a `#!python options = ...` parameter that can be used to customize its behavior. You can provide a `#!python reactpy_django.types.MutationOptions` object to this parameter to customize the hook's behavior.
193205

194-
The example below is a merge of the `#!python use_query` and `#!python use_mutation` examples above with the addition of a `#!python use_mutation(refetch=...)` argument.
206+
Below are the settings that can be modified via `#!python MutationOptions`.
195207

196-
Please note that any `#!python use_query` hooks that use `#!python get_items` will be refetched upon a successful mutation.
208+
---
209+
210+
<font size="4">**`#!python thread_sensitive`**</font>
211+
212+
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 [`#!python sync_to_async` docs](https://docs.djangoproject.com/en/dev/topics/async/#sync-to-async) docs for more information.
213+
214+
This setting only applies to sync query functions, and will be ignored for async functions.
197215

198216
=== "components.py"
199217

200218
```python
201-
{% include "../../python/use-mutation-query-refetch.py" %}
219+
{% include "../../python/use-mutation-thread-sensitive.py" %}
202220
```
203221

204-
=== "models.py"
222+
??? question "Can I make ORM calls without hooks?"
205223

206-
```python
207-
{% include "../../python/example/models.py" %}
208-
```
224+
{% include-markdown "../../includes/orm.md" start="<!--orm-excp-start-->" end="<!--orm-excp-end-->" %}
209225

210-
??? question "Can I make a failed `#!python use_mutation` try again?"
226+
??? question "Can I make a failed mutation try again?"
211227

212228
Yes, a `#!python use_mutation` can be re-performed by calling `#!python reset()` on your `#!python use_mutation` instance.
213229

@@ -225,13 +241,29 @@ The mutation function you provide should have no return value.
225241
{% include "../../python/example/models.py" %}
226242
```
227243

228-
??? question "Can I make ORM calls without hooks?"
244+
??? question "Can `#!python use_mutation` trigger a refetch of `#!python use_query`?"
229245

230-
{% include-markdown "../../includes/orm.md" start="<!--orm-excp-start-->" end="<!--orm-excp-end-->" %}
246+
Yes, `#!python use_mutation` can queue a refetch of a `#!python use_query` via the `#!python refetch=...` argument.
247+
248+
The example below is a merge of the `#!python use_query` and `#!python use_mutation` examples above with the addition of a `#!python use_mutation(refetch=...)` argument.
249+
250+
Please note that `refetch` will cause all `#!python use_query` hooks that use `#!python get_items` in the current component tree will be refetched.
251+
252+
=== "components.py"
253+
254+
```python
255+
{% include "../../python/use-mutation-query-refetch.py" %}
256+
```
257+
258+
=== "models.py"
259+
260+
```python
261+
{% include "../../python/example/models.py" %}
262+
```
231263

232264
## Use Connection
233265

234-
This hook is used to fetch the Django Channels [WebSocket](https://channels.readthedocs.io/en/stable/topics/consumers.html#asyncjsonwebsocketconsumer).
266+
This hook is used to fetch the active connection, which is either a Django [WebSocket](https://channels.readthedocs.io/en/stable/topics/consumers.html#asyncjsonwebsocketconsumer) or a [HTTP Request](https://docs.djangoproject.com/en/4.2/ref/request-response/#django.http.HttpRequest).
235267

236268
=== "components.py"
237269

@@ -249,11 +281,11 @@ This hook is used to fetch the Django Channels [WebSocket](https://channels.read
249281

250282
| Type | Description |
251283
| --- | --- |
252-
| `#!python Connection` | The component's WebSocket. |
284+
| `#!python Connection` | The component's `WebSocket` or `HttpRequest`. |
253285

254286
## Use Scope
255287

256-
This is a shortcut that returns the WebSocket's [`#!python scope`](https://channels.readthedocs.io/en/stable/topics/consumers.html#scope).
288+
This is a shortcut that returns the HTTP or WebSocket [`#!python scope`](https://channels.readthedocs.io/en/stable/topics/consumers.html#scope).
257289

258290
=== "components.py"
259291

@@ -275,7 +307,7 @@ This is a shortcut that returns the WebSocket's [`#!python scope`](https://chann
275307

276308
## Use Location
277309

278-
This is a shortcut that returns the WebSocket's `#!python path`.
310+
This is a shortcut that returns the client's `#!python path`.
279311

280312
You can expect this hook to provide strings such as `/reactpy/my_path`.
281313

@@ -299,7 +331,7 @@ You can expect this hook to provide strings such as `/reactpy/my_path`.
299331

300332
??? info "This hook's behavior will be changed in a future update"
301333

302-
This hook will be updated to return the browser's currently active HTTP path. This change will come in alongside ReactPy URL routing support.
334+
This hook will be updated to always return the browser's currently active HTTP path. This change will come in alongside ReactPy URL routing support.
303335

304336
Check out [reactive-python/reactpy-django#147](https://github.com/reactive-python/reactpy-django/issues/147) for more information.
305337

@@ -325,4 +357,4 @@ You can expect this hook to provide strings such as `http://example.com`.
325357

326358
| Type | Description |
327359
| --- | --- |
328-
| `#!python str | None` | A string containing the browser's current origin, obtained from WebSocket headers (if available). |
360+
| `#!python str | None` | A string containing the browser's current origin, obtained from WebSocket or HTTP headers (if available). |

docs/src/reference/settings.md

+1-1
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 global default `#!python reactpy_django.hooks.use_query` postprocessor function.
3838

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

docs/src/reference/template-tag.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ This template tag can be used to insert any number of ReactPy components onto yo
8181
Here's a couple of things to keep in mind:
8282

8383
1. If your host address are completely separate ( `origin1.com != origin2.com` ) you will need to [configure CORS headers](https://pypi.org/project/django-cors-headers/) on your main application during deployment.
84-
2. You will not need to register ReactPy HTTP or WebSocket paths on any applications that do not perform any component rendering.
84+
2. You will not need to register ReactPy WebSocket or HTTP paths on any applications that do not perform any component rendering.
8585
3. Your component will only be able to access your template tag's `#!python *args`/`#!python **kwargs` if your applications share a common database.
8686

8787
<!--multiple-components-start-->

0 commit comments

Comments
 (0)