Skip to content

Commit 2b64f17

Browse files
Adds ADD_ASSET_PREFIX setting for configuring staticfiles url prefix (#226)
1 parent 2c2b69c commit 2b64f17

File tree

5 files changed

+79
-5
lines changed

5 files changed

+79
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/
1818

1919
## [Unreleased]
2020

21+
### Added
22+
23+
- Added new `ADD_ASSET_PREFIX` setting to control how the app label prefix is added to asset URLs. This setting provides more flexibility than the previous DEBUG-based behavior, especially useful in test environments.
24+
2125
### Fixed
2226

2327
- Fixed path normalization in asset manifest to prevent double-prefixing of already normalized paths (e.g., preventing "app:app:templates/file.html").

docs/configuration.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ from pathlib import Path
5858
DJANGO_BIRD = {
5959
"COMPONENT_DIRS": list[Path | str] = [],
6060
"ENABLE_BIRD_ATTRS": bool = True,
61+
"ADD_ASSET_PREFIX": bool | None = None,
6162
}
6263
```
6364

@@ -110,3 +111,25 @@ The default `bird` directory will always be checked last, ensuring that your cus
110111
Controls whether components automatically receive data attributes related to django-bird in its `attrs` template context variable. Defaults to `True`.
111112

112113
See [Component ID Attribute](params.md#component-id-attribute) for more details on how this works.
114+
115+
### `ADD_ASSET_PREFIX`
116+
117+
Controls whether the app label prefix (`django_bird/`) is added to component asset URLs. This setting has three possible values:
118+
119+
- `None` (default): Automatically add the prefix in production (when `DEBUG = False`) but not in development mode. This matches Django's standard behavior where staticfiles are served directly from source directories in development but collected into a central location in production.
120+
121+
- `True`: Always add the prefix, regardless of the `DEBUG` setting. This is useful if you want consistent URL paths in all environments.
122+
123+
- `False`: Never add the prefix, regardless of the `DEBUG` setting. This is useful for custom static file configurations or when you're manually managing the directory structure.
124+
125+
#### Example Use Cases
126+
127+
- **Testing Environment**: In test environments, especially with Playwright or Selenium e2e tests, you may want to set:
128+
129+
```python
130+
DJANGO_BIRD = {"ADD_ASSET_PREFIX": False}
131+
```
132+
133+
This ensures your tests can find static assets without the prefix, even when `DEBUG = False`.
134+
135+
- **Custom Static File Handling**: If you have a custom static file setup that doesn't follow Django's conventions, you can configure the appropriate value based on your needs.

src/django_bird/conf.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
class AppSettings:
2020
COMPONENT_DIRS: list[Path | str] = field(default_factory=list)
2121
ENABLE_BIRD_ATTRS: bool = True
22+
ADD_ASSET_PREFIX: bool | None = None
2223

2324
@override
2425
def __getattribute__(self, __name: str) -> object:
@@ -28,5 +29,13 @@ def __getattribute__(self, __name: str) -> object:
2829
def get_component_directory_names(self):
2930
return unique_ordered([*self.COMPONENT_DIRS, "bird"])
3031

32+
def should_add_asset_prefix(self) -> bool:
33+
"""Determine if the app label prefix should be added to asset URLs."""
34+
if self.ADD_ASSET_PREFIX is not None:
35+
return self.ADD_ASSET_PREFIX
36+
37+
# Fall back to the DEBUG setting (add prefix in production)
38+
return not settings.DEBUG
39+
3140

3241
app_settings = AppSettings()

src/django_bird/staticfiles.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from typing import final
1313
from typing import overload
1414

15-
from django.conf import settings
1615
from django.contrib.staticfiles import finders
1716
from django.contrib.staticfiles.finders import BaseFinder
1817
from django.contrib.staticfiles.storage import StaticFilesStorage
@@ -179,11 +178,16 @@ def __init__(self, *args: Any, prefix: str, **kwargs: Any):
179178
def url(self, name: str | None) -> str:
180179
if name is None:
181180
return super().url(name)
182-
# Only add prefix in production (when DEBUG is False)
181+
# Determine if we should add the prefix based on the app settings
182+
from .conf import app_settings
183+
184+
# Add prefix based on app settings configuration
183185
# In development, asset paths don't include the app label prefix
184-
# because they come directly from source directories and in production,
185-
# assets are collected to STATIC_ROOT/django_bird/
186-
if not settings.DEBUG and not name.startswith(f"{self.prefix}/"):
186+
# because they come directly from source directories
187+
# In production, assets are collected to STATIC_ROOT/django_bird/
188+
if app_settings.should_add_asset_prefix() and not name.startswith(
189+
f"{self.prefix}/"
190+
):
187191
name = f"{self.prefix}/{name}"
188192
return super().url(name)
189193

tests/test_staticfiles.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,40 @@ def test_url(self, DEBUG, expected_prefix, templates_dir):
225225
== f"{expected_prefix}/{button_css.file.parent.name}/{button_css.file.name}"
226226
)
227227

228+
@pytest.mark.parametrize(
229+
"add_prefix,DEBUG,expected_prefix",
230+
[
231+
(None, False, "/static/django_bird"),
232+
(None, True, "/static"),
233+
(True, False, "/static/django_bird"),
234+
(True, True, "/static/django_bird"),
235+
(False, False, "/static"),
236+
(False, True, "/static"),
237+
],
238+
)
239+
def test_url_with_add_asset_prefix(
240+
self, add_prefix, DEBUG, expected_prefix, templates_dir, override_app_settings
241+
):
242+
button = TestComponent(
243+
name="button",
244+
content="<button>Click me</button>",
245+
).create(templates_dir)
246+
button_css = TestAsset(
247+
component=button,
248+
content=".button { color: blue; }",
249+
asset_type=CSS,
250+
).create()
251+
252+
component = Component.from_name(button.name)
253+
asset = component.get_asset(button_css.file.name)
254+
255+
with override_settings(DEBUG=DEBUG):
256+
with override_app_settings(ADD_ASSET_PREFIX=add_prefix):
257+
assert (
258+
asset.url
259+
== f"{expected_prefix}/{button_css.file.parent.name}/{button_css.file.name}"
260+
)
261+
228262
def test_url_nonexistent(self, templates_dir):
229263
button = TestComponent(
230264
name="button",

0 commit comments

Comments
 (0)