mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-25 00:36:11 -06:00
Extend search backend to filter by object type
This commit is contained in:
parent
79c6bec195
commit
e66902c05c
@ -23,7 +23,8 @@ class LookupTypes:
|
|||||||
def get_registry():
|
def get_registry():
|
||||||
r = {}
|
r = {}
|
||||||
for app_label, models in registry['search'].items():
|
for app_label, models in registry['search'].items():
|
||||||
r.update(**models)
|
for model_name, idx in models.items():
|
||||||
|
r[f'{app_label}.{model_name}'] = idx
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
@ -51,19 +51,20 @@ class SearchBackend:
|
|||||||
for app_label, models in registry['search'].items():
|
for app_label, models in registry['search'].items():
|
||||||
for name, cls in models.items():
|
for name, cls in models.items():
|
||||||
title = cls.model._meta.verbose_name.title()
|
title = cls.model._meta.verbose_name.title()
|
||||||
categories[cls.get_category()][name] = title
|
value = f'{app_label}.{name}'
|
||||||
|
categories[cls.get_category()][value] = title
|
||||||
|
|
||||||
# Compile a nested tuple of choices for form rendering
|
# Compile a nested tuple of choices for form rendering
|
||||||
results = (
|
results = (
|
||||||
('', 'All Objects'),
|
('', 'All Objects'),
|
||||||
*[(category, choices.items()) for category, choices in categories.items()]
|
*[(category, list(choices.items())) for category, choices in categories.items()]
|
||||||
)
|
)
|
||||||
|
|
||||||
self._search_choice_options = results
|
self._search_choice_options = results
|
||||||
|
|
||||||
return self._search_choice_options
|
return self._search_choice_options
|
||||||
|
|
||||||
def search(self, request, value, lookup=DEFAULT_LOOKUP_TYPE):
|
def search(self, request, value, object_types=None, lookup=DEFAULT_LOOKUP_TYPE):
|
||||||
"""
|
"""
|
||||||
Search cached object representations for the given value.
|
Search cached object representations for the given value.
|
||||||
"""
|
"""
|
||||||
@ -114,11 +115,16 @@ class FilterSetSearchBackend(SearchBackend):
|
|||||||
Legacy search backend. Performs a discrete database query for each registered object type, using the FilterSet
|
Legacy search backend. Performs a discrete database query for each registered object type, using the FilterSet
|
||||||
class specified by the index for each.
|
class specified by the index for each.
|
||||||
"""
|
"""
|
||||||
def search(self, request, value, lookup=DEFAULT_LOOKUP_TYPE):
|
def search(self, request, value, object_types=None, lookup=DEFAULT_LOOKUP_TYPE):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
search_registry = get_registry()
|
search_registry = get_registry()
|
||||||
for obj_type in search_registry.keys():
|
if object_types is not None:
|
||||||
|
keys = [f'{ct.app_label}.{ct.name}' for ct in object_types]
|
||||||
|
else:
|
||||||
|
keys = search_registry.keys()
|
||||||
|
|
||||||
|
for obj_type in keys:
|
||||||
|
|
||||||
queryset = getattr(search_registry[obj_type], 'queryset', None)
|
queryset = getattr(search_registry[obj_type], 'queryset', None)
|
||||||
if not queryset:
|
if not queryset:
|
||||||
@ -154,16 +160,17 @@ class FilterSetSearchBackend(SearchBackend):
|
|||||||
|
|
||||||
class CachedValueSearchBackend(SearchBackend):
|
class CachedValueSearchBackend(SearchBackend):
|
||||||
|
|
||||||
def search(self, request, value, lookup=DEFAULT_LOOKUP_TYPE):
|
def search(self, request, value, object_types=None, lookup=DEFAULT_LOOKUP_TYPE):
|
||||||
|
|
||||||
# Define the search parameters
|
# Define the search parameters
|
||||||
# TODO: Filter object types to only those which the use has permission to view
|
|
||||||
params = {
|
params = {
|
||||||
f'value__{lookup}': value
|
f'value__{lookup}': value
|
||||||
}
|
}
|
||||||
if lookup != LookupTypes.EXACT:
|
if lookup != LookupTypes.EXACT:
|
||||||
# Partial matches are valid only on string values
|
# Partial matches are valid only on string values
|
||||||
params['type'] = FieldTypes.STRING
|
params['type'] = FieldTypes.STRING
|
||||||
|
if object_types:
|
||||||
|
params['object_type__in'] = object_types
|
||||||
|
|
||||||
# Construct the base queryset to retrieve matching results
|
# Construct the base queryset to retrieve matching results
|
||||||
queryset = CachedValue.objects.filter(**params).annotate(
|
queryset = CachedValue.objects.filter(**params).annotate(
|
||||||
|
@ -2,6 +2,7 @@ import platform
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.http import HttpResponseServerError
|
from django.http import HttpResponseServerError
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
@ -150,17 +151,19 @@ class SearchView(View):
|
|||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
form = SearchForm(request.GET)
|
form = SearchForm(request.GET)
|
||||||
|
object_types = None
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
# If an object type has been specified, redirect to the dedicated view for it
|
|
||||||
if form.cleaned_data['obj_type']:
|
|
||||||
search_registry = get_registry()
|
|
||||||
object_type = form.cleaned_data['obj_type']
|
|
||||||
url = reverse(search_registry[object_type].url)
|
|
||||||
return redirect(f"{url}?q={form.cleaned_data['q']}")
|
|
||||||
|
|
||||||
results = search_backend.search(request, form.cleaned_data['q'])
|
# Restrict results by object type
|
||||||
|
if form.cleaned_data['obj_type']:
|
||||||
|
app_label, model_name = form.cleaned_data['obj_type'].split('.')
|
||||||
|
object_types = [
|
||||||
|
ContentType.objects.get_by_natural_key(app_label, model_name)
|
||||||
|
]
|
||||||
|
|
||||||
|
results = search_backend.search(request, form.cleaned_data['q'], object_types=object_types)
|
||||||
|
|
||||||
return render(request, 'search.html', {
|
return render(request, 'search.html', {
|
||||||
'form': form,
|
'form': form,
|
||||||
|
Loading…
Reference in New Issue
Block a user