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),
|
('description', 500),
|
||||||
('comments', 5000),
|
('comments', 5000),
|
||||||
)
|
)
|
||||||
|
display_attrs = ('site', 'location', 'rack', 'device_type', 'description')
|
||||||
|
|
||||||
|
|
||||||
@register_search
|
@register_search
|
||||||
@ -282,6 +283,7 @@ class SiteIndex(SearchIndex):
|
|||||||
('shipping_address', 2000),
|
('shipping_address', 2000),
|
||||||
('comments', 5000),
|
('comments', 5000),
|
||||||
)
|
)
|
||||||
|
display_attrs = ('region', 'group', 'status', 'description')
|
||||||
|
|
||||||
|
|
||||||
@register_search
|
@register_search
|
||||||
|
@ -4,7 +4,9 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from netbox.registry import registry
|
||||||
from utilities.fields import RestrictedGenericForeignKey
|
from utilities.fields import RestrictedGenericForeignKey
|
||||||
|
from utilities.utils import content_type_identifier
|
||||||
from ..fields import CachedValueField
|
from ..fields import CachedValueField
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -56,3 +58,16 @@ class CachedValue(models.Model):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'{self.object_type} {self.object_id}: {self.field}={self.value}'
|
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,
|
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.
|
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.
|
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
|
model = None
|
||||||
category = None
|
category = None
|
||||||
fields = ()
|
fields = ()
|
||||||
|
display_attrs = ()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_field_type(instance, field_name):
|
def get_field_type(instance, field_name):
|
||||||
|
@ -3,7 +3,8 @@ from collections import defaultdict
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
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.functions import window
|
||||||
from django.db.models.signals import post_delete, post_save
|
from django.db.models.signals import post_delete, post_save
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
@ -13,7 +14,7 @@ from netaddr.core import AddrFormatError
|
|||||||
from extras.models import CachedValue, CustomField
|
from extras.models import CachedValue, CustomField
|
||||||
from netbox.registry import registry
|
from netbox.registry import registry
|
||||||
from utilities.querysets import RestrictedPrefetch
|
from utilities.querysets import RestrictedPrefetch
|
||||||
from utilities.utils import title
|
from utilities.utils import content_type_identifier, title
|
||||||
from . import FieldTypes, LookupTypes, get_indexer
|
from . import FieldTypes, LookupTypes, get_indexer
|
||||||
|
|
||||||
DEFAULT_LOOKUP_TYPE = LookupTypes.PARTIAL
|
DEFAULT_LOOKUP_TYPE = LookupTypes.PARTIAL
|
||||||
@ -129,6 +130,10 @@ class CachedValueSearchBackend(SearchBackend):
|
|||||||
)
|
)
|
||||||
)[:MAX_RESULTS]
|
)[: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
|
# Construct a Prefetch to pre-fetch only those related objects for which the
|
||||||
# user has permission to view.
|
# user has permission to view.
|
||||||
if user:
|
if user:
|
||||||
@ -144,12 +149,31 @@ class CachedValueSearchBackend(SearchBackend):
|
|||||||
params
|
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
|
# Omit any results pertaining to an object the user does not have permission to view
|
||||||
ret = []
|
ret = []
|
||||||
for r in results:
|
for r in results:
|
||||||
if r.object is not None:
|
if r.object is not None:
|
||||||
r.name = str(r.object)
|
r.name = str(r.object)
|
||||||
ret.append(r)
|
ret.append(r)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def cache(self, instances, indexer=None, remove_existing=True):
|
def cache(self, instances, indexer=None, remove_existing=True):
|
||||||
|
@ -15,6 +15,7 @@ from extras.choices import CustomFieldVisibilityChoices
|
|||||||
from netbox.tables import columns
|
from netbox.tables import columns
|
||||||
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
||||||
from utilities.utils import get_viewname, highlight_string, title
|
from utilities.utils import get_viewname, highlight_string, title
|
||||||
|
from .template_code import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'BaseTable',
|
'BaseTable',
|
||||||
@ -236,6 +237,10 @@ class SearchTable(tables.Table):
|
|||||||
value = tables.Column(
|
value = tables.Column(
|
||||||
verbose_name=_('Value'),
|
verbose_name=_('Value'),
|
||||||
)
|
)
|
||||||
|
attrs = columns.TemplateColumn(
|
||||||
|
template_code=SEARCH_RESULT_ATTRS,
|
||||||
|
verbose_name=_('Attributes')
|
||||||
|
)
|
||||||
|
|
||||||
trim_length = 30
|
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