You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a `SynchronousOnlyOperation` exception.
4
+
5
+
These `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.
6
+
7
+
<!--orm-excp-end-->
8
+
9
+
<!--orm-fetch-start-->
10
+
11
+
By default, automatic recursive fetching of `ManyToMany` or `ForeignKey` fields is enabled within the default `QueryOptions.postprocessor`. This is needed to prevent `SynchronousOnlyOperation` exceptions when accessing these fields within your IDOM components.
@@ -64,87 +64,120 @@ The function you provide into this hook must return either a `Model` or `QuerySe
64
64
| --- | --- |
65
65
| `Query[_Result | None]` | 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. |
66
66
67
-
??? question "Can I make ORM calls without hooks?"
67
+
??? question "How can I provide arguments to my query function?"
68
+
69
+
`*args` and `**kwargs` can be provided to your query function via `use_query` parameters.
70
+
71
+
=== "components.py"
68
72
69
-
Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a `SynchronousOnlyOperation` exception.
73
+
```python
74
+
from idom import component
75
+
from django_idom.hooks import use_query
70
76
71
-
This compatibility may be resolved in a future version of Django containing an asynchronous ORM. However, it is still best practice to always perform ORM calls in the background via `use_query`.
??? question "Why does the example `get_items` function return `TodoItem.objects.all()`?"
92
+
93
+
This was a technical design decision to based on [Apollo's `useQuery` hook](https://www.apollographql.com/docs/react/data/queries/), but ultimately helps avoid Django's `SynchronousOnlyOperation` exceptions.
94
+
95
+
The `use_query` hook ensures the provided `Model` or `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.
72
96
73
97
??? question "Can this hook be used for things other than the Django ORM?"
1. Want to use this hook to defer IO intensive tasks to be computed in the background
78
104
2. Want to to utilize `use_query` with a different ORM
79
105
80
-
... then you can disable all postprocessing behavior by modifying the `postprocessor` parameter in `QueryOptions`.
106
+
... then you can disable all postprocessing behavior by modifying the `QueryOptions.postprocessor` parameter. In the example below, we will set the `postprocessor` to a function that takes one argument and returns nothing.
81
107
82
-
```python
83
-
from django_idom.types import QueryOptions
84
-
from django_idom.hooks import use_query
108
+
=== "components.py"
85
109
86
-
def io_intensive_operation():
87
-
"""This is an example function call that does something IO intensive, but can
88
-
potentially fail to execute."""
89
-
...
110
+
```python
111
+
from idom import component
112
+
from django_idom.types import QueryOptions
113
+
from django_idom.hooks import use_query
90
114
91
-
@component
92
-
def todo_list():
93
-
query = use_query(
94
-
io_intensive_operation,
95
-
QueryOptions(
96
-
# By setting the postprocessor to a function that takes one argument
97
-
# and returns None, we can disable postprocessing behavior.
98
-
postprocessor=lambda data: None,
99
-
),
100
-
)
115
+
def execute_io_intensive_operation():
116
+
"""This is an example query function that does something IO intensive."""
117
+
pass
101
118
102
-
if query.loading or query.error:
103
-
return None
119
+
@component
120
+
def todo_list():
121
+
query = use_query(
122
+
execute_io_intensive_operation,
123
+
QueryOptions(
124
+
# By setting the postprocessor to a function that takes one argument
125
+
# and returns None, we can disable postprocessing behavior.
126
+
postprocessor=lambda data: None,
127
+
),
128
+
)
104
129
105
-
return str(query.data)
106
-
```
130
+
if query.loading or query.error:
131
+
return None
107
132
108
-
??? question "Can this hook automatically fetch `ManyToMany` fields or `ForeignKey` relationships?"
133
+
return str(query.data)
134
+
```
109
135
110
-
By default, automatic recursive fetching of `ManyToMany` or `ForeignKey` fields is disabled for performance reasons.
136
+
??? question "How can I prevent this hook from recursively fetching `ManyToMany`fields or `ForeignKey`relationships?"
111
137
112
-
If you wish you enable this feature, you can modify the `postprocessor_kwargs` parameter in `QueryOptions`.
However, if you have deep nested trees of relational data, this may not be a desirable behavior. You may prefer to manually fetch these relational fields using a second `use_query` hook.
118
141
119
-
def model_with_relationships():
120
-
"""This is an example function that gets `MyModel` that has a ManyToMany field, and
121
-
additionally other models that have formed a ForeignKey association to `MyModel`.
142
+
You can disable the prefetching behavior of the default `postprocessor` (located at `django_idom.utils.django_query_postprocessor`) via the `QueryOptions.postprocessor_kwargs` parameter.
Please note that due Django's ORM design, the field name to access foreign keys is [always be postfixed with `_set`](https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_one/).
This was a technical design decision to [based on Apollo](https://www.apollographql.com/docs/react/data/mutations/#usemutation-api), but ultimately helps avoid Django's `SynchronousOnlyOperation` exceptions.
176
+
_Note: In Django's ORM design, the field name to access foreign keys is [always be postfixed with `_set`](https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_one/)._
146
177
147
-
The `use_query` hook ensures the provided `Model` or `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.
178
+
??? question "Can I make ORM calls without hooks?"
@@ -202,6 +235,28 @@ The function you provide into this hook will have no return value.
202
235
| --- | --- |
203
236
| `Mutation[_Params]` | An object containing `loading`/`error` states, a `reset` callable that will set `loading`/`error` states to defaults, and a `execute` callable that will run the query. |
204
237
238
+
??? question "How can I provide arguments to my mutation function?"
239
+
240
+
`*args` and `**kwargs` can be provided to your mutation function via `mutation.execute` parameters.
0 commit comments