|
| 1 | +import logging |
| 2 | + |
1 | 3 | from django import template |
| 4 | +from django.templatetags.static import static |
2 | 5 | from django.utils.safestring import mark_safe |
| 6 | +from urllib.parse import urlparse, urlunparse, parse_qs, urlencode |
3 | 7 |
|
4 | 8 | from extras.choices import CustomFieldTypeChoices |
5 | 9 | from utilities.querydict import dict_to_querydict |
|
11 | 15 | 'customfield_value', |
12 | 16 | 'htmx_table', |
13 | 17 | 'formaction', |
| 18 | + 'static_with_params', |
14 | 19 | 'tag', |
15 | 20 | ) |
16 | 21 |
|
@@ -127,3 +132,53 @@ def formaction(context): |
127 | 132 | if context.get('htmx_navigation', False): |
128 | 133 | return mark_safe('hx-push-url="true" hx-post') |
129 | 134 | return 'formaction' |
| 135 | + |
| 136 | + |
| 137 | +@register.simple_tag |
| 138 | +def static_with_params(path, **params): |
| 139 | + """ |
| 140 | + Generate a static URL with properly appended query parameters. |
| 141 | +
|
| 142 | + The original Django static tag doesn't properly handle appending new parameters to URLs |
| 143 | + that already contain query parameters, which can result in malformed URLs with double |
| 144 | + question marks. This template tag handles the case where static files are served from |
| 145 | + AWS S3 or other CDNs that automatically append query parameters to URLs. |
| 146 | +
|
| 147 | + This implementation correctly appends new parameters to existing URLs and checks for |
| 148 | + parameter conflicts. A warning will be logged if any of the provided parameters |
| 149 | + conflict with existing parameters in the URL. |
| 150 | +
|
| 151 | + Args: |
| 152 | + path: The static file path (e.g., 'setmode.js') |
| 153 | + **params: Query parameters to append (e.g., v='4.3.1') |
| 154 | +
|
| 155 | + Returns: |
| 156 | + A properly formatted URL with query parameters. |
| 157 | +
|
| 158 | + Note: |
| 159 | + If any provided parameters conflict with existing URL parameters, a warning |
| 160 | + will be logged and the new parameter value will override the existing one. |
| 161 | + """ |
| 162 | + # Get the base static URL |
| 163 | + static_url = static(path) |
| 164 | + |
| 165 | + # Parse the URL to extract existing query parameters |
| 166 | + parsed = urlparse(static_url) |
| 167 | + existing_params = parse_qs(parsed.query) |
| 168 | + |
| 169 | + # Check for duplicate parameters and log warnings |
| 170 | + logger = logging.getLogger('netbox.utilities.templatetags.tags') |
| 171 | + for key, value in params.items(): |
| 172 | + if key in existing_params: |
| 173 | + logger.warning( |
| 174 | + f"Parameter '{key}' already exists in static URL '{static_url}' " |
| 175 | + f"with value(s) {existing_params[key]}, overwriting with '{value}'" |
| 176 | + ) |
| 177 | + existing_params[key] = [str(value)] |
| 178 | + |
| 179 | + # Rebuild the query string |
| 180 | + new_query = urlencode(existing_params, doseq=True) |
| 181 | + |
| 182 | + # Reconstruct the URL with the new query string |
| 183 | + new_parsed = parsed._replace(query=new_query) |
| 184 | + return urlunparse(new_parsed) |
0 commit comments