Extend reindex command to support specifying particular models

This commit is contained in:
jeremystretch 2022-10-19 15:40:06 -04:00
parent 80b9caa537
commit 50088ef393

View File

@ -1,4 +1,5 @@
from django.core.management.base import BaseCommand from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand, CommandError
from extras.models import CachedValue from extras.models import CachedValue
from extras.registry import registry from extras.registry import registry
@ -6,20 +7,71 @@ from netbox.search.backends import search_backend
class Command(BaseCommand): class Command(BaseCommand):
"""Reindex cached search values""" help = 'Reindex objects for search'
help = 'Reindex cached search values.'
def handle(self, *args, **kwargs): def add_arguments(self, parser):
parser.add_argument(
'args',
metavar='app_label[.ModelName]',
nargs='*',
help='One or more apps or models to reindex',
)
self.stdout.write('Clearing cached values...', ending="\n") def _get_indexers(self, *model_names):
CachedValue.objects.all().delete() indexers = {}
for app_label, models in registry['search'].items(): # No models specified; pull in all registered indexers
for name, idx in models.items(): if not model_names:
self.stdout.write(f'Reindexing {app_label}.{name}...', ending="\n") for app_label, models in registry['search'].items():
model = idx.model for _, idx in models.items():
for instance in model.objects.all(): indexers[idx.model] = idx
search_backend.caching_handler(model, instance)
# Return only indexers for the specified models
else:
for label in model_names:
try:
app_label, model_name = label.lower().split('.')
except ValueError:
raise CommandError(
f"Invalid model: {label}. Model names must be in the format <app_label>.<model_name>."
)
try:
idx = registry['search'][app_label][model_name]
indexers[idx.model] = idx
except KeyError:
raise CommandError(f"No indexer found for {label}")
return indexers
def handle(self, *model_labels, **kwargs):
# Determine which models to reindex
indexers = self._get_indexers(*model_labels)
if not indexers:
raise CommandError("No indexers found!")
self.stdout.write(f'Reindexing {len(indexers)} models.')
# Clear all cached values for the specified models
self.stdout.write('Clearing cached values... ', ending='')
if model_labels:
content_types = [
ContentType.objects.get_for_model(model) for model in indexers.keys()
]
del_count, _ = CachedValue.objects.filter(object_type__in=content_types).delete()
else:
del_count, _ = CachedValue.objects.all().delete()
self.stdout.write(f'{del_count} deleted.')
# Index models
for model, idx in indexers.items():
app_label = model._meta.app_label
model_name = model._meta.model_name
self.stdout.write(f'Reindexing {app_label}.{model_name}... ', ending='')
i = 0
for i, instance in enumerate(model.objects.all()):
search_backend.caching_handler(model, instance)
if i:
self.stdout.write(f'{i} created.')
cache_size = CachedValue.objects.count() cache_size = CachedValue.objects.count()
self.stdout.write(f'Done. Generated {cache_size} cached values', ending="\n") self.stdout.write(f'Done. Finished with {cache_size} cached values')