diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 32f4ded32..6656aa1bb 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -16,6 +16,7 @@ * [#12627](https://github.com/netbox-community/netbox/issues/12627) - Restore hover preview for embedded image attachment tables * [#12694](https://github.com/netbox-community/netbox/issues/12694) - Strip leading & trailing whitespace from custom link URL & text * [#12715](https://github.com/netbox-community/netbox/issues/12715) - Use contact assignments table to display the contacts assigned to an object +* [#12742](https://github.com/netbox-community/netbox/issues/12742) - Object counts dashboard widget should support URL-compatible query filters * [#12745](https://github.com/netbox-community/netbox/issues/12745) - Escape display text in API-backed selection widgets --- diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py index dc68e1388..ed50a8451 100644 --- a/netbox/extras/dashboard/widgets.py +++ b/netbox/extras/dashboard/widgets.py @@ -10,8 +10,9 @@ from django.conf import settings 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, reverse +from django.urls import NoReverseMatch, resolve, reverse from django.utils.translation import gettext as _ from extras.utils import FeatureQuery @@ -149,7 +150,7 @@ class ObjectCountsWidget(DashboardWidget): filters = forms.JSONField( required=False, label='Object filters', - help_text=_("Only objects matching the specified filters will be counted") + help_text=_("Filters to apply when counting the number of objects") ) def clean_filters(self): @@ -158,13 +159,6 @@ class ObjectCountsWidget(DashboardWidget): dict(data) except TypeError: raise forms.ValidationError("Invalid format. Object filters must be passed as a dictionary.") - for model in get_models_from_content_types(self.cleaned_data.get('models')): - try: - # Validate the filters by creating a QuerySet - model.objects.filter(**data).none() - except Exception: - model_name = model._meta.verbose_name_plural - raise forms.ValidationError(f"Invalid filter specification for {model_name}.") return data def render(self, request): @@ -172,9 +166,14 @@ class ObjectCountsWidget(DashboardWidget): for model in get_models_from_content_types(self.config['models']): permission = get_permission_for_model(model, 'view') if request.user.has_perm(permission): + url = reverse(get_viewname(model, 'list')) qs = model.objects.restrict(request.user, 'view') + # Apply any specified filters if filters := self.config.get('filters'): - qs = qs.filter(**filters) + params = QueryDict(mutable=True) + params.update(filters) + filterset = getattr(resolve(url).func.view_class, 'filterset', None) + qs = filterset(params, qs).qs object_count = qs.count counts.append((model, object_count)) else: