Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions netbox/extras/dashboard/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache
from django.db.models import Q
from django.http import QueryDict
from django.template.loader import render_to_string
from django.urls import NoReverseMatch, resolve, reverse
from django.utils.translation import gettext as _
Expand All @@ -19,7 +18,7 @@
from utilities.forms import BootstrapMixin
from utilities.permissions import get_permission_for_model
from utilities.templatetags.builtins.filters import render_markdown
from utilities.utils import content_type_identifier, content_type_name, get_viewname
from utilities.utils import content_type_identifier, content_type_name, dict_to_querydict, get_viewname
from .utils import register_widget

__all__ = (
Expand Down Expand Up @@ -170,8 +169,7 @@ def render(self, request):
qs = model.objects.restrict(request.user, 'view')
# Apply any specified filters
if filters := self.config.get('filters'):
params = QueryDict(mutable=True)
params.update(filters)
params = dict_to_querydict(filters)
filterset = getattr(resolve(url).func.view_class, 'filterset', None)
qs = filterset(params, qs).qs
url = f'{url}?{params.urlencode()}'
Expand Down
7 changes: 3 additions & 4 deletions netbox/extras/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.core.cache import cache
from django.core.validators import ValidationError
from django.db import models
from django.http import HttpResponse, QueryDict
from django.http import HttpResponse
from django.urls import reverse
from django.utils import timezone
from django.utils.formats import date_format
Expand All @@ -26,7 +26,7 @@
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin,
)
from utilities.querysets import RestrictedQuerySet
from utilities.utils import clean_html, render_jinja2
from utilities.utils import clean_html, dict_to_querydict, render_jinja2

__all__ = (
'ConfigRevision',
Expand Down Expand Up @@ -462,8 +462,7 @@ def clean(self):

@property
def url_params(self):
qd = QueryDict(mutable=True)
qd.update(self.parameters)
qd = dict_to_querydict(self.parameters)
return qd.urlencode()


Expand Down
5 changes: 3 additions & 2 deletions netbox/utilities/templatetags/builtins/tags.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django import template
from django.http import QueryDict

from utilities.utils import dict_to_querydict

__all__ = (
'badge',
'checkmark',
Expand Down Expand Up @@ -87,8 +89,7 @@ def htmx_table(context, viewname, return_url=None, **kwargs):
viewname: The name of the view to use for the HTMX request (e.g. `dcim:site_list`)
return_url: The URL to pass as the `return_url`. If not provided, the current request's path will be used.
"""
url_params = QueryDict(mutable=True)
url_params.update(kwargs)
url_params = dict_to_querydict(kwargs)
url_params['return_url'] = return_url or context['request'].path
return {
'viewname': viewname,
Expand Down
16 changes: 15 additions & 1 deletion netbox/utilities/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
from django.db.models import Count, OuterRef, Subquery
from django.db.models.functions import Coalesce
from django.http import QueryDict
from django.utils.html import escape
from django.utils import timezone
from django.utils.datastructures import MultiValueDict
from django.utils.html import escape
from django.utils.timezone import localtime
from jinja2.sandbox import SandboxedEnvironment
from mptt.models import MPTTModel
Expand Down Expand Up @@ -231,6 +232,19 @@ def dict_to_filter_params(d, prefix=''):
return params


def dict_to_querydict(d, mutable=True):
"""
Create a QueryDict instance from a regular Python dictionary.
"""
qd = QueryDict(mutable=True)
for k, v in d.items():
item = MultiValueDict({k: v}) if isinstance(v, (list, tuple, set)) else {k: v}
qd.update(item)
if not mutable:
qd._mutable = False
return qd


def normalize_querydict(querydict):
"""
Convert a QueryDict to a normal, mutable dictionary, preserving list values. For example,
Expand Down