Skip to content

Commit 82c80c3

Browse files
authored
Allow settings.py postprocessor to be None (#182)
1 parent 7a3657a commit 82c80c3

File tree

8 files changed

+44
-12
lines changed

8 files changed

+44
-12
lines changed

Diff for: CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ Using the following categories, list your changes in this order:
3838

3939
- Warning W018 (`Suspicious position of 'reactpy_django' in INSTALLED_APPS`) has been added.
4040

41+
### Changed
42+
43+
- The default postprocessor can now disabled by setting `REACTPY_DEFAULT_QUERY_POSTPROCESSOR` to `None`.
44+
4145
## [3.5.0] - 2023-08-26
4246

4347
### Added

Diff for: docs/src/features/settings.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ These are ReactPy-Django's default settings values. You can modify these values
2626
| `REACTPY_DATABASE` | `#!python "default"` | `#!python "my-reactpy-database"` | Database used to store ReactPy session data. ReactPy requires a multiprocessing-safe and thread-safe database.<br/>If configuring `REACTPY_DATABASE`, it is mandatory to use our database router like such:<br/>`#!python DATABASE_ROUTERS = ["reactpy_django.database.Router", ...]` |
2727
| `REACTPY_SESSION_MAX_AGE` | `#!python 259200` | `#!python 0`, `#!python 60`, `#!python 96000` | Maximum seconds to store ReactPy session data, such as `args` and `kwargs` passed into your component template tag.<br/>Use `#!python 0` to not store any session data. |
2828
| `REACTPY_URL_PREFIX` | `#!python "reactpy/"` | `#!python "rp/"`, `#!python "render/reactpy/"` | The prefix to be used for all ReactPy websocket and HTTP URLs. |
29-
| `REACTPY_DEFAULT_QUERY_POSTPROCESSOR` | `#!python "reactpy_django.utils.django_query_postprocessor"` | `#!python "example_project.my_query_postprocessor"` | Dotted path to the default `reactpy_django.hooks.use_query` postprocessor function. |
29+
| `REACTPY_DEFAULT_QUERY_POSTPROCESSOR` | `#!python "reactpy_django.utils.django_query_postprocessor"` | `#!python None`, `#!python "example_project.my_query_postprocessor"` | Dotted path to the default `reactpy_django.hooks.use_query` postprocessor function. Postprocessor functions can be async or sync, and the parameters must contain the arg `#!python data`. Set `REACTPY_DEFAULT_QUERY_POSTPROCESSOR` to `#!python None` to globally disable the default postprocessor. |
3030
| `REACTPY_AUTH_BACKEND` | `#!python "django.contrib.auth.backends.ModelBackend"` | `#!python "example_project.auth.MyModelBackend"` | Dotted path to the Django authentication backend to use for ReactPy components. This is only needed if:<br/> 1. You are using `AuthMiddlewareStack` and...<br/> 2. You are using Django's `AUTHENTICATION_BACKENDS` setting and...<br/> 3. Your Django user model does not define a `backend` attribute. |
3131
| `REACTPY_BACKHAUL_THREAD` | `#!python False` | `#!python True` | Whether to render ReactPy components in a dedicated thread. This allows the webserver to process web traffic while during ReactPy rendering.<br/>Vastly improves throughput with web servers such as `hypercorn` and `uvicorn`. |
3232
| `REACTPY_DEFAULT_HOSTS` | `#!python None` | `#!python ["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.<br/>You can use the `host` argument in your [template tag](../features/template-tag.md#component) as a manual override. |

Diff for: src/reactpy_django/checks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,12 @@ def reactpy_errors(app_configs, **kwargs):
330330
)
331331
)
332332
if not isinstance(
333-
getattr(settings, "REACTPY_DEFAULT_QUERY_POSTPROCESSOR", ""), str
333+
getattr(settings, "REACTPY_DEFAULT_QUERY_POSTPROCESSOR", ""), (str, type(None))
334334
):
335335
errors.append(
336336
Error(
337337
"Invalid type for REACTPY_DEFAULT_QUERY_POSTPROCESSOR.",
338-
hint="REACTPY_DEFAULT_QUERY_POSTPROCESSOR should be a string.",
338+
hint="REACTPY_DEFAULT_QUERY_POSTPROCESSOR should be a string or None.",
339339
obj=settings.REACTPY_DEFAULT_QUERY_POSTPROCESSOR,
340340
id="reactpy_django.E007",
341341
)

Diff for: src/reactpy_django/config.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,20 @@
5353
_default_query_postprocessor = getattr(
5454
settings,
5555
"REACTPY_DEFAULT_QUERY_POSTPROCESSOR",
56-
None,
56+
"UNSET",
5757
)
58-
REACTPY_DEFAULT_QUERY_POSTPROCESSOR: AsyncPostprocessor | SyncPostprocessor | None = (
59-
import_dotted_path(
60-
_default_query_postprocessor
61-
if isinstance(_default_query_postprocessor, str)
62-
else "reactpy_django.utils.django_query_postprocessor",
58+
REACTPY_DEFAULT_QUERY_POSTPROCESSOR: AsyncPostprocessor | SyncPostprocessor | None
59+
if _default_query_postprocessor is None:
60+
REACTPY_DEFAULT_QUERY_POSTPROCESSOR = None
61+
else:
62+
REACTPY_DEFAULT_QUERY_POSTPROCESSOR = import_dotted_path(
63+
"reactpy_django.utils.django_query_postprocessor"
64+
if (
65+
_default_query_postprocessor == "UNSET"
66+
or not isinstance(_default_query_postprocessor, str)
67+
)
68+
else _default_query_postprocessor
6369
)
64-
)
6570
REACTPY_AUTH_BACKEND: str | None = getattr(
6671
settings,
6772
"REACTPY_AUTH_BACKEND",

Diff for: src/reactpy_django/types.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ class QueryOptions:
105105
are optional `postprocessor_kwargs` (see below). This postprocessor function must return
106106
the modified `data`.
107107
108-
If `None`, the default postprocessor is used.
108+
If unset, REACTPY_DEFAULT_QUERY_POSTPROCESSOR is used.
109109
110-
This default Django query postprocessor prevents Django's lazy query execution, and
110+
ReactPy's default django_query_postprocessor prevents Django's lazy query execution, and
111111
additionally can be configured via `postprocessor_kwargs` to recursively fetch
112112
`many_to_many` and `many_to_one` fields."""
113113

Diff for: tests/test_app/components.py

+15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from django.shortcuts import render
99
from reactpy import component, hooks, html, web
1010
from reactpy_django.components import view_to_component
11+
from reactpy_django.types import QueryOptions
1112

1213
from test_app.models import (
1314
AsyncForiegnChild,
@@ -602,3 +603,17 @@ def custom_host(number=0):
602603
},
603604
f"Server Port: {port}",
604605
)
606+
607+
608+
@component
609+
def broken_postprocessor_query():
610+
relational_parent = reactpy_django.hooks.use_query(
611+
QueryOptions(postprocessor=None), get_relational_parent_query
612+
)
613+
614+
if not relational_parent.data:
615+
return
616+
617+
mtm = relational_parent.data.many_to_many.all()
618+
619+
return html.div(f"This should have failed! Something went wrong: {mtm}")

Diff for: tests/test_app/templates/base.html

+3
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ <h1>ReactPy Test Page</h1>
9191
<hr>
9292
<div id="invalid_host_error">{% component "test_app.components.hello_world" host="https://example.com/" %}</div>
9393
<hr>
94+
<div id="broken_postprocessor_query">
95+
{% component "test_app.components.broken_postprocessor_query" %}</div>
96+
<hr>
9497
</body>
9598

9699
</html>

Diff for: tests/test_app/tests/test_components.py

+5
Original file line numberDiff line numberDiff line change
@@ -370,3 +370,8 @@ def test_invalid_host_error(self):
370370
broken_component = self.page.locator("#invalid_host_error")
371371
broken_component.wait_for()
372372
self.assertIn("InvalidHostError:", broken_component.text_content())
373+
374+
def test_broken_postprocessor_query(self):
375+
broken_component = self.page.locator("#broken_postprocessor_query pre")
376+
broken_component.wait_for()
377+
self.assertIn("SynchronousOnlyOperation:", broken_component.text_content())

0 commit comments

Comments
 (0)