From 5d7ed871f257a412276b1a7fe862533872132631 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 11 Apr 2025 12:26:46 -0400 Subject: [PATCH] Fixes: #18783 Add a tag_id filter for all models which support tagging (#18889) (#19142) --- docs/plugins/development/filtersets.md | 21 +++++++++++++++++++++ netbox/extras/filters.py | 16 ++++++++++++++++ netbox/extras/filtersets.py | 3 ++- netbox/netbox/filtersets.py | 3 ++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/plugins/development/filtersets.md b/docs/plugins/development/filtersets.md index 224802397..e19b3a733 100644 --- a/docs/plugins/development/filtersets.md +++ b/docs/plugins/development/filtersets.md @@ -61,6 +61,11 @@ class MyModelViewSet(...): The `TagFilter` class is available for all models which support tag assignment (those which inherit from `NetBoxModel` or `TagsMixin`). This filter subclasses django-filter's `ModelMultipleChoiceFilter` to work with NetBox's `TaggedItem` class. +This class filters `tags` using the `slug` field. For example: + +`GET /api/dcim/sites/?tag=alpha&tag=bravo` + + ```python from django_filters import FilterSet from extras.filters import TagFilter @@ -68,3 +73,19 @@ from extras.filters import TagFilter class MyModelFilterSet(FilterSet): tag = TagFilter() ``` + +### TagIDFilter + +The `TagIDFilter` class is available for all models which support tag assignment (those which inherit from `NetBoxModel` or `TagsMixin`). This filter subclasses django-filter's `ModelMultipleChoiceFilter` to work with NetBox's `TaggedItem` class. + +This class filters `tags` using the `id` field. For example: + +`GET /api/dcim/sites/?tag_id=100&tag_id=200` + +```python +from django_filters import FilterSet +from extras.filters import TagIDFilter + +class MyModelFilterSet(FilterSet): + tag_id = TagIDFilter() +``` diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index de739aa59..d05800c22 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -4,6 +4,7 @@ from .models import Tag __all__ = ( 'TagFilter', + 'TagIDFilter', ) @@ -20,3 +21,18 @@ class TagFilter(django_filters.ModelMultipleChoiceFilter): kwargs.setdefault('queryset', Tag.objects.all()) super().__init__(*args, **kwargs) + + +class TagIDFilter(django_filters.ModelMultipleChoiceFilter): + """ + Match on one or more assigned tags. If multiple tags are specified (e.g. ?tag=1&tag=2), the queryset is filtered + to objects matching all tags. + """ + def __init__(self, *args, **kwargs): + + kwargs.setdefault('field_name', 'tags__id') + kwargs.setdefault('to_field_name', 'id') + kwargs.setdefault('conjoined', True) + kwargs.setdefault('queryset', Tag.objects.all()) + + super().__init__(*args, **kwargs) diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index f03359fcf..6adad110d 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -13,7 +13,7 @@ from utilities.filters import ( ) from virtualization.models import Cluster, ClusterGroup, ClusterType from .choices import * -from .filters import TagFilter +from .filters import TagFilter, TagIDFilter from .models import * __all__ = ( @@ -758,6 +758,7 @@ class ConfigTemplateFilterSet(ChangeLoggedModelFilterSet): label=_('Data file (ID)'), ) tag = TagFilter() + tag_id = TagIDFilter() class Meta: model = ConfigTemplate diff --git a/netbox/netbox/filtersets.py b/netbox/netbox/filtersets.py index ffae9b7ff..f24b4e11c 100644 --- a/netbox/netbox/filtersets.py +++ b/netbox/netbox/filtersets.py @@ -12,7 +12,7 @@ from django.utils.translation import gettext as _ from core.choices import ObjectChangeActionChoices from core.models import ObjectChange from extras.choices import CustomFieldFilterLogicChoices -from extras.filters import TagFilter +from extras.filters import TagFilter, TagIDFilter from extras.models import CustomField, SavedFilter from utilities.constants import ( FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP, @@ -289,6 +289,7 @@ class NetBoxModelFilterSet(ChangeLoggedModelFilterSet): label=_('Search'), ) tag = TagFilter() + tag_id = TagIDFilter() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs)