Repository: netbox-community/netbox
Pull request: 12433 update object list widget to correctly parameterize urls
### Fixes: #12433 

Moves the page_size concatenation for object list view widget from the template to the widget code so parameter concatenation is done correctly.

Problem statement:
Dashboard widgets incorrectly concatenate params
### NetBox version

v3.5.0

### Python version

3.8

### Steps to Reproduce

1. create a new widget of object list configuration
2. choose model "DCIM > Site"
3. Put "10" in Page size
4. put {"tenant_id": 5} in URL parameters
5. click save

### Expected Behavior

widget will show list based on filtered params.

### Observed Behavior

All sites are shown. Debugging shows the URL passed to the view is "?tenant_id=5?page_size=10" (note the two "?") correct url should have "&" as the param separator.

Hints from issue discussion:

Commit message: 12433 update object list widget to correctly parameterize urls

Patch to review:
diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py
index 9cd53763a6e..0aba01d2946 100644
--- a/netbox/extras/dashboard/widgets.py
+++ b/netbox/extras/dashboard/widgets.py
@@ -229,7 +229,13 @@ def render(self, request):
             htmx_url = reverse(viewname)
         except NoReverseMatch:
             htmx_url = None
-        if parameters := self.config.get('url_params'):
+        parameters = self.config.get('url_params')
+        if page_size := self.config.get('page_size'):
+            if not parameters:
+                parameters = {}
+            parameters['page_size'] = page_size
+
+        if parameters:
             try:
                 htmx_url = f'{htmx_url}?{urlencode(parameters, doseq=True)}'
             except ValueError:
@@ -238,7 +244,6 @@ def render(self, request):
             'viewname': viewname,
             'has_permission': has_permission,
             'htmx_url': htmx_url,
-            'page_size': self.config.get('page_size'),
         })
 
 
diff --git a/netbox/templates/extras/dashboard/widgets/objectlist.html b/netbox/templates/extras/dashboard/widgets/objectlist.html
index 76c4e658cdc..54f8094b326 100644
--- a/netbox/templates/extras/dashboard/widgets/objectlist.html
+++ b/netbox/templates/extras/dashboard/widgets/objectlist.html
@@ -1,5 +1,5 @@
 {% if htmx_url and has_permission %}
-  <div class="htmx-container" hx-get="{{ htmx_url }}{% if page_size %}?per_page={{ page_size }}{% endif %}" hx-trigger="load"></div>
+  <div class="htmx-container" hx-get="{{ htmx_url }}" hx-trigger="load"></div>
 {% elif htmx_url %}
   <div class="text-muted text-center">
     <i class="mdi mdi-lock-outline"></i> No permission to view this content.


Code review comments:
diff_hunk: @@ -229,7 +229,13 @@ def render(self, request):
             htmx_url = reverse(viewname)
         except NoReverseMatch:
             htmx_url = None
-        if parameters := self.config.get('url_params'):
+        parameters = self.config.get('url_params')
+        if page_size := self.config.get('page_size'):
+            if not parameters:
+                parameters = {}
+            parameters['page_size'] = page_size
path: netbox/extras/dashboard/widgets.py
text: @user1:
We can clean this up a bit by passing `{}` as the default for null `url_params`.
```suggestion
        parameters = self.config.get('url_params', {})
        if page_size := self.config.get('page_size'):
          parameters['page_size'] = page_size
```