mirror of
https://github.com/django-components/django-components.git
synced 2025-11-17 21:57:07 +00:00
refactor: add missing exports, better error handling, and handle boolean query params (#1422)
Some checks are pending
Docs - build & deploy / docs (push) Waiting to run
Run tests / build (ubuntu-latest, 3.10) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.11) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.12) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.13) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.8) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.9) (push) Waiting to run
Run tests / build (windows-latest, 3.10) (push) Waiting to run
Run tests / build (windows-latest, 3.11) (push) Waiting to run
Run tests / build (windows-latest, 3.12) (push) Waiting to run
Run tests / build (windows-latest, 3.13) (push) Waiting to run
Run tests / build (windows-latest, 3.8) (push) Waiting to run
Run tests / build (windows-latest, 3.9) (push) Waiting to run
Run tests / test_docs (3.13) (push) Waiting to run
Run tests / test_sampleproject (3.13) (push) Waiting to run
Some checks are pending
Docs - build & deploy / docs (push) Waiting to run
Run tests / build (ubuntu-latest, 3.10) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.11) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.12) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.13) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.8) (push) Waiting to run
Run tests / build (ubuntu-latest, 3.9) (push) Waiting to run
Run tests / build (windows-latest, 3.10) (push) Waiting to run
Run tests / build (windows-latest, 3.11) (push) Waiting to run
Run tests / build (windows-latest, 3.12) (push) Waiting to run
Run tests / build (windows-latest, 3.13) (push) Waiting to run
Run tests / build (windows-latest, 3.8) (push) Waiting to run
Run tests / build (windows-latest, 3.9) (push) Waiting to run
Run tests / test_docs (3.13) (push) Waiting to run
Run tests / test_sampleproject (3.13) (push) Waiting to run
This commit is contained in:
parent
e9d1b6c4b2
commit
8957befd1a
14 changed files with 552 additions and 371 deletions
|
|
@ -34,7 +34,6 @@ from django_components.component_registry import (
|
|||
registry,
|
||||
all_registries,
|
||||
)
|
||||
from django_components.components import DynamicComponent
|
||||
from django_components.dependencies import DependenciesStrategy, render_dependencies
|
||||
from django_components.extension import (
|
||||
ComponentExtension,
|
||||
|
|
@ -47,6 +46,10 @@ from django_components.extension import (
|
|||
OnComponentClassDeletedContext,
|
||||
OnComponentInputContext,
|
||||
OnComponentDataContext,
|
||||
OnComponentRenderedContext,
|
||||
OnSlotRenderedContext,
|
||||
OnTemplateCompiledContext,
|
||||
OnTemplateLoadedContext,
|
||||
)
|
||||
from django_components.extensions.cache import ComponentCache
|
||||
from django_components.extensions.defaults import ComponentDefaults, Default
|
||||
|
|
@ -81,6 +84,9 @@ from django_components.util.loader import ComponentFileEntry, get_component_dirs
|
|||
from django_components.util.routing import URLRoute, URLRouteHandler
|
||||
from django_components.util.types import Empty
|
||||
|
||||
# NOTE: Import built-in components last to avoid circular imports
|
||||
from django_components.components import DynamicComponent
|
||||
|
||||
# isort: on
|
||||
|
||||
|
||||
|
|
@ -122,10 +128,14 @@ __all__ = [
|
|||
"OnComponentDataContext",
|
||||
"OnComponentInputContext",
|
||||
"OnComponentRegisteredContext",
|
||||
"OnComponentRenderedContext",
|
||||
"OnComponentUnregisteredContext",
|
||||
"OnRegistryCreatedContext",
|
||||
"OnRegistryDeletedContext",
|
||||
"OnRenderGenerator",
|
||||
"OnSlotRenderedContext",
|
||||
"OnTemplateCompiledContext",
|
||||
"OnTemplateLoadedContext",
|
||||
"ProvideNode",
|
||||
"RegistrySettings",
|
||||
"ShorthandComponentFormatter",
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@ def get_component_url(
|
|||
|
||||
`get_component_url()` optionally accepts `query` and `fragment` arguments.
|
||||
|
||||
**Query parameter handling:**
|
||||
|
||||
- `True` values are rendered as flag parameters without values (e.g., `?enabled`)
|
||||
- `False` and `None` values are omitted from the URL
|
||||
- Other values are rendered normally (e.g., `?foo=bar`)
|
||||
|
||||
**Example:**
|
||||
|
||||
```py
|
||||
|
|
@ -60,10 +66,10 @@ def get_component_url(
|
|||
# Get the URL for the component
|
||||
url = get_component_url(
|
||||
MyComponent,
|
||||
query={"foo": "bar"},
|
||||
query={"foo": "bar", "enabled": True, "debug": False, "unused": None},
|
||||
fragment="baz",
|
||||
)
|
||||
# /components/ext/view/components/c1ab2c3?foo=bar#baz
|
||||
# /components/ext/view/components/c1ab2c3?foo=bar&enabled#baz
|
||||
```
|
||||
"""
|
||||
view_cls: Optional[Type[ComponentView]] = getattr(component, "View", None)
|
||||
|
|
|
|||
|
|
@ -20,20 +20,27 @@ def component_error_message(component_path: List[str]) -> Generator[None, None,
|
|||
components = getattr(err, "_components", [])
|
||||
components = err._components = [*component_path, *components] # type: ignore[attr-defined]
|
||||
|
||||
# Access the exception's message, see https://stackoverflow.com/a/75549200/9788634
|
||||
if len(err.args) and err.args[0] is not None:
|
||||
if not components:
|
||||
orig_msg = str(err.args[0])
|
||||
else:
|
||||
orig_msg = str(err.args[0]).split("\n", 1)[-1]
|
||||
else:
|
||||
orig_msg = str(err)
|
||||
|
||||
# Format component path as
|
||||
# "MyPage > MyComponent > MyComponent(slot:content) > Base(slot:tab)"
|
||||
comp_path = " > ".join(components)
|
||||
prefix = f"An error occured while rendering components {comp_path}:\n"
|
||||
|
||||
# Access the exception's message, see https://stackoverflow.com/a/75549200/9788634
|
||||
if len(err.args) and err.args[0] is not None:
|
||||
orig_msg = str(err.args[0])
|
||||
if components and "An error occured while rendering components" in orig_msg:
|
||||
orig_msg = str(err.args[0]).split("\n", 1)[-1]
|
||||
else:
|
||||
# When the exception has no message, it may be that the exception
|
||||
# does NOT rely on the `args` attribute. Such case is for example
|
||||
# Pydantic exceptions.
|
||||
#
|
||||
# In this case, we still try to use the `args` attribute, but
|
||||
# it's not guaranteed to work. So we also print out the component
|
||||
# path ourselves.
|
||||
print(prefix) # noqa: T201
|
||||
orig_msg = str(err)
|
||||
|
||||
err.args = (prefix + orig_msg,) # tuple of one
|
||||
|
||||
# `from None` should still raise the original error, but without showing this
|
||||
|
|
|
|||
|
|
@ -162,12 +162,35 @@ def format_url(url: str, query: Optional[Dict] = None, fragment: Optional[str] =
|
|||
```
|
||||
|
||||
`query` and `fragment` are optional, and not applied if `None`.
|
||||
|
||||
Boolean `True` values in query parameters are rendered as flag parameters without values.
|
||||
|
||||
`False` and `None` values in query parameters are omitted.
|
||||
|
||||
```py
|
||||
url = format_url(
|
||||
url="https://example.com",
|
||||
query={"foo": "bar", "baz": None, "enabled": True, "debug": False},
|
||||
)
|
||||
# https://example.com?foo=bar&enabled
|
||||
```
|
||||
"""
|
||||
parts = parse.urlsplit(url)
|
||||
fragment_enc = parse.quote(fragment or parts.fragment, safe="")
|
||||
base_qs = dict(parse.parse_qsl(parts.query))
|
||||
merged = {**base_qs, **(query or {})}
|
||||
encoded_qs = parse.urlencode(merged, safe="")
|
||||
# Filter out `None` and `False` values
|
||||
filtered_query = {k: v for k, v in (query or {}).items() if v is not None and v is not False}
|
||||
merged = {**base_qs, **filtered_query}
|
||||
|
||||
# Handle boolean True values as flag parameters (no explicit value)
|
||||
query_parts = []
|
||||
for key, value in merged.items():
|
||||
if value is True:
|
||||
query_parts.append(parse.quote_plus(str(key)))
|
||||
else:
|
||||
query_parts.append(f"{parse.quote_plus(str(key))}={parse.quote_plus(str(value))}")
|
||||
|
||||
encoded_qs = "&".join(query_parts)
|
||||
|
||||
return parse.urlunsplit(parts._replace(query=encoded_qs, fragment=fragment_enc))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue