diff --git a/CHANGELOG.md b/CHANGELOG.md
index 80b9d021..40f29365 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,6 +38,10 @@ Using the following categories, list your changes in this order:
- Warning W018 (`Suspicious position of 'reactpy_django' in INSTALLED_APPS`) has been added.
+### Changed
+
+- The default postprocessor can now disabled by setting `REACTPY_DEFAULT_QUERY_POSTPROCESSOR` to `None`.
+
## [3.5.0] - 2023-08-26
### Added
diff --git a/docs/src/features/settings.md b/docs/src/features/settings.md
index 00662976..3917d766 100644
--- a/docs/src/features/settings.md
+++ b/docs/src/features/settings.md
@@ -26,7 +26,7 @@ These are ReactPy-Django's default settings values. You can modify these values
| `REACTPY_DATABASE` | `#!python "default"` | `#!python "my-reactpy-database"` | Database used to store ReactPy session data. ReactPy requires a multiprocessing-safe and thread-safe database.
If configuring `REACTPY_DATABASE`, it is mandatory to use our database router like such:
`#!python DATABASE_ROUTERS = ["reactpy_django.database.Router", ...]` |
| `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.
Use `#!python 0` to not store any session data. |
| `REACTPY_URL_PREFIX` | `#!python "reactpy/"` | `#!python "rp/"`, `#!python "render/reactpy/"` | The prefix to be used for all ReactPy websocket and HTTP URLs. |
-| `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. |
+| `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. |
| `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:
1. You are using `AuthMiddlewareStack` and...
2. You are using Django's `AUTHENTICATION_BACKENDS` setting and...
3. Your Django user model does not define a `backend` attribute. |
| `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.
Vastly improves throughput with web servers such as `hypercorn` and `uvicorn`. |
| `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.
You can use the `host` argument in your [template tag](../features/template-tag.md#component) as a manual override. |
diff --git a/src/reactpy_django/checks.py b/src/reactpy_django/checks.py
index e7d320d6..adc437d0 100644
--- a/src/reactpy_django/checks.py
+++ b/src/reactpy_django/checks.py
@@ -330,12 +330,12 @@ def reactpy_errors(app_configs, **kwargs):
)
)
if not isinstance(
- getattr(settings, "REACTPY_DEFAULT_QUERY_POSTPROCESSOR", ""), str
+ getattr(settings, "REACTPY_DEFAULT_QUERY_POSTPROCESSOR", ""), (str, type(None))
):
errors.append(
Error(
"Invalid type for REACTPY_DEFAULT_QUERY_POSTPROCESSOR.",
- hint="REACTPY_DEFAULT_QUERY_POSTPROCESSOR should be a string.",
+ hint="REACTPY_DEFAULT_QUERY_POSTPROCESSOR should be a string or None.",
obj=settings.REACTPY_DEFAULT_QUERY_POSTPROCESSOR,
id="reactpy_django.E007",
)
diff --git a/src/reactpy_django/config.py b/src/reactpy_django/config.py
index d811f7dc..dc350e2a 100644
--- a/src/reactpy_django/config.py
+++ b/src/reactpy_django/config.py
@@ -53,15 +53,20 @@
_default_query_postprocessor = getattr(
settings,
"REACTPY_DEFAULT_QUERY_POSTPROCESSOR",
- None,
+ "UNSET",
)
-REACTPY_DEFAULT_QUERY_POSTPROCESSOR: AsyncPostprocessor | SyncPostprocessor | None = (
- import_dotted_path(
- _default_query_postprocessor
- if isinstance(_default_query_postprocessor, str)
- else "reactpy_django.utils.django_query_postprocessor",
+REACTPY_DEFAULT_QUERY_POSTPROCESSOR: AsyncPostprocessor | SyncPostprocessor | None
+if _default_query_postprocessor is None:
+ REACTPY_DEFAULT_QUERY_POSTPROCESSOR = None
+else:
+ REACTPY_DEFAULT_QUERY_POSTPROCESSOR = import_dotted_path(
+ "reactpy_django.utils.django_query_postprocessor"
+ if (
+ _default_query_postprocessor == "UNSET"
+ or not isinstance(_default_query_postprocessor, str)
+ )
+ else _default_query_postprocessor
)
-)
REACTPY_AUTH_BACKEND: str | None = getattr(
settings,
"REACTPY_AUTH_BACKEND",
diff --git a/src/reactpy_django/types.py b/src/reactpy_django/types.py
index ac6205e0..233fe432 100644
--- a/src/reactpy_django/types.py
+++ b/src/reactpy_django/types.py
@@ -105,9 +105,9 @@ class QueryOptions:
are optional `postprocessor_kwargs` (see below). This postprocessor function must return
the modified `data`.
- If `None`, the default postprocessor is used.
+ If unset, REACTPY_DEFAULT_QUERY_POSTPROCESSOR is used.
- This default Django query postprocessor prevents Django's lazy query execution, and
+ ReactPy's default django_query_postprocessor prevents Django's lazy query execution, and
additionally can be configured via `postprocessor_kwargs` to recursively fetch
`many_to_many` and `many_to_one` fields."""
diff --git a/tests/test_app/components.py b/tests/test_app/components.py
index d018cd96..ec53c031 100644
--- a/tests/test_app/components.py
+++ b/tests/test_app/components.py
@@ -8,6 +8,7 @@
from django.shortcuts import render
from reactpy import component, hooks, html, web
from reactpy_django.components import view_to_component
+from reactpy_django.types import QueryOptions
from test_app.models import (
AsyncForiegnChild,
@@ -602,3 +603,17 @@ def custom_host(number=0):
},
f"Server Port: {port}",
)
+
+
+@component
+def broken_postprocessor_query():
+ relational_parent = reactpy_django.hooks.use_query(
+ QueryOptions(postprocessor=None), get_relational_parent_query
+ )
+
+ if not relational_parent.data:
+ return
+
+ mtm = relational_parent.data.many_to_many.all()
+
+ return html.div(f"This should have failed! Something went wrong: {mtm}")
diff --git a/tests/test_app/templates/base.html b/tests/test_app/templates/base.html
index 303e99dd..03dd3ba3 100644
--- a/tests/test_app/templates/base.html
+++ b/tests/test_app/templates/base.html
@@ -91,6 +91,9 @@