mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-23 07:56:44 -06:00
WIP
This commit is contained in:
parent
77208bf5f3
commit
fa25c2c983
@ -44,6 +44,7 @@ class DeviceIndex(SearchIndex):
|
||||
('description', 500),
|
||||
('comments', 5000),
|
||||
)
|
||||
display_attrs = ('site', 'location', 'rack', 'device_type', 'description')
|
||||
|
||||
|
||||
@register_search
|
||||
@ -282,6 +283,7 @@ class SiteIndex(SearchIndex):
|
||||
('shipping_address', 2000),
|
||||
('comments', 5000),
|
||||
)
|
||||
display_attrs = ('region', 'group', 'status', 'description')
|
||||
|
||||
|
||||
@register_search
|
||||
|
@ -4,7 +4,9 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from netbox.registry import registry
|
||||
from utilities.fields import RestrictedGenericForeignKey
|
||||
from utilities.utils import content_type_identifier
|
||||
from ..fields import CachedValueField
|
||||
|
||||
__all__ = (
|
||||
@ -56,3 +58,16 @@ class CachedValue(models.Model):
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.object_type} {self.object_id}: {self.field}={self.value}'
|
||||
|
||||
@property
|
||||
def display_attrs(self):
|
||||
indexer = registry['search'].get(content_type_identifier(self.object_type))
|
||||
attrs = {}
|
||||
for attr in getattr(indexer, 'display_attrs', []):
|
||||
name = self.object._meta.get_field(attr).verbose_name
|
||||
if value := getattr(self.object, attr):
|
||||
if display_func := getattr(self.object, f'get_{attr}_display', None):
|
||||
attrs[name] = display_func()
|
||||
else:
|
||||
attrs[name] = value
|
||||
return attrs
|
||||
|
@ -33,10 +33,12 @@ class SearchIndex:
|
||||
category: The label of the group under which this indexer is categorized (for form field display). If none,
|
||||
the name of the model's app will be used.
|
||||
fields: An iterable of two-tuples defining the model fields to be indexed and the weight associated with each.
|
||||
display_attrs: An iterable of additional object attributes to include when displaying search results.
|
||||
"""
|
||||
model = None
|
||||
category = None
|
||||
fields = ()
|
||||
display_attrs = ()
|
||||
|
||||
@staticmethod
|
||||
def get_field_type(instance, field_name):
|
||||
|
@ -3,7 +3,8 @@ from collections import defaultdict
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models import F, Window, Q
|
||||
from django.db.models import F, Window, Q, prefetch_related_objects
|
||||
from django.db.models.fields.related import ForeignKey
|
||||
from django.db.models.functions import window
|
||||
from django.db.models.signals import post_delete, post_save
|
||||
from django.utils.module_loading import import_string
|
||||
@ -13,7 +14,7 @@ from netaddr.core import AddrFormatError
|
||||
from extras.models import CachedValue, CustomField
|
||||
from netbox.registry import registry
|
||||
from utilities.querysets import RestrictedPrefetch
|
||||
from utilities.utils import title
|
||||
from utilities.utils import content_type_identifier, title
|
||||
from . import FieldTypes, LookupTypes, get_indexer
|
||||
|
||||
DEFAULT_LOOKUP_TYPE = LookupTypes.PARTIAL
|
||||
@ -129,6 +130,10 @@ class CachedValueSearchBackend(SearchBackend):
|
||||
)
|
||||
)[:MAX_RESULTS]
|
||||
|
||||
# Find the ContentTypes for all objects present in the search results
|
||||
content_type_ids = set(queryset.values_list('object_type', flat=True))
|
||||
content_types = ContentType.objects.filter(pk__in=content_type_ids)
|
||||
|
||||
# Construct a Prefetch to pre-fetch only those related objects for which the
|
||||
# user has permission to view.
|
||||
if user:
|
||||
@ -144,12 +149,31 @@ class CachedValueSearchBackend(SearchBackend):
|
||||
params
|
||||
)
|
||||
|
||||
# Prefetch display attributes
|
||||
for ct in content_types:
|
||||
model = ct.model_class()
|
||||
indexer = registry['search'].get(content_type_identifier(ct))
|
||||
display_attrs = getattr(indexer, 'display_attrs', None)
|
||||
if not display_attrs:
|
||||
continue
|
||||
|
||||
prefetch_fields = []
|
||||
for attr in display_attrs:
|
||||
field = model._meta.get_field(attr)
|
||||
if type(field) is ForeignKey:
|
||||
prefetch_fields.append(f'object__{attr}')
|
||||
|
||||
if prefetch_fields:
|
||||
objects = [r for r in results if r.object_type == ct]
|
||||
prefetch_related_objects(objects, *prefetch_fields)
|
||||
|
||||
# Omit any results pertaining to an object the user does not have permission to view
|
||||
ret = []
|
||||
for r in results:
|
||||
if r.object is not None:
|
||||
r.name = str(r.object)
|
||||
ret.append(r)
|
||||
|
||||
return ret
|
||||
|
||||
def cache(self, instances, indexer=None, remove_existing=True):
|
||||
|
@ -15,6 +15,7 @@ from extras.choices import CustomFieldVisibilityChoices
|
||||
from netbox.tables import columns
|
||||
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
||||
from utilities.utils import get_viewname, highlight_string, title
|
||||
from .template_code import *
|
||||
|
||||
__all__ = (
|
||||
'BaseTable',
|
||||
@ -236,6 +237,10 @@ class SearchTable(tables.Table):
|
||||
value = tables.Column(
|
||||
verbose_name=_('Value'),
|
||||
)
|
||||
attrs = columns.TemplateColumn(
|
||||
template_code=SEARCH_RESULT_ATTRS,
|
||||
verbose_name=_('Attributes')
|
||||
)
|
||||
|
||||
trim_length = 30
|
||||
|
||||
|
5
netbox/netbox/tables/template_code.py
Normal file
5
netbox/netbox/tables/template_code.py
Normal file
@ -0,0 +1,5 @@
|
||||
SEARCH_RESULT_ATTRS = """
|
||||
{% for name, value in record.display_attrs.items %}
|
||||
<span class="badge bg-secondary">{{ name|bettertitle }}: {{ value }}</span>
|
||||
{% endfor %}
|
||||
"""
|
Loading…
Reference in New Issue
Block a user