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():
|
||||
r = {}
|
||||
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
|
||||
|
||||
|
@ -51,19 +51,20 @@ class SearchBackend:
|
||||
for app_label, models in registry['search'].items():
|
||||
for name, cls in models.items():
|
||||
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
|
||||
results = (
|
||||
('', '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
|
||||
|
||||
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.
|
||||
"""
|
||||
@ -114,11 +115,16 @@ class FilterSetSearchBackend(SearchBackend):
|
||||
Legacy search backend. Performs a discrete database query for each registered object type, using the FilterSet
|
||||
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 = []
|
||||
|
||||
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)
|
||||
if not queryset:
|
||||
@ -154,16 +160,17 @@ class FilterSetSearchBackend(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
|
||||
# TODO: Filter object types to only those which the use has permission to view
|
||||
params = {
|
||||
f'value__{lookup}': value
|
||||
}
|
||||
if lookup != LookupTypes.EXACT:
|
||||
# Partial matches are valid only on string values
|
||||
params['type'] = FieldTypes.STRING
|
||||
if object_types:
|
||||
params['object_type__in'] = object_types
|
||||
|
||||
# Construct the base queryset to retrieve matching results
|
||||
queryset = CachedValue.objects.filter(**params).annotate(
|
||||
|
@ -2,6 +2,7 @@ import platform
|
||||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.cache import cache
|
||||
from django.http import HttpResponseServerError
|
||||
from django.shortcuts import redirect, render
|
||||
@ -150,17 +151,19 @@ class SearchView(View):
|
||||
|
||||
def get(self, request):
|
||||
form = SearchForm(request.GET)
|
||||
object_types = None
|
||||
results = []
|
||||
|
||||
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', {
|
||||
'form': form,
|
||||
|
Loading…
Reference in New Issue
Block a user