diff --git a/netbox/extras/models/change_logging.py b/netbox/extras/models/change_logging.py index e2b118b84..00a8feec7 100644 --- a/netbox/extras/models/change_logging.py +++ b/netbox/extras/models/change_logging.py @@ -5,7 +5,7 @@ from django.db import models from django.urls import reverse from extras.choices import * -from utilities.querysets import RestrictedQuerySet +from ..querysets import ObjectChangeManager __all__ = ( 'ObjectChange', @@ -82,7 +82,7 @@ class ObjectChange(models.Model): null=True ) - objects = RestrictedQuerySet.as_manager() + objects = ObjectChangeManager() class Meta: ordering = ['-time'] diff --git a/netbox/extras/querysets.py b/netbox/extras/querysets.py index 2b97af0fb..5462a3477 100644 --- a/netbox/extras/querysets.py +++ b/netbox/extras/querysets.py @@ -1,5 +1,6 @@ +from django.conf import settings from django.contrib.postgres.aggregates import JSONBAgg -from django.db.models import OuterRef, Subquery, Q +from django.db.models import Manager, OuterRef, Subquery, Q from extras.models.tags import TaggedItem from utilities.query_functions import EmptyGroupByJSONBAgg @@ -151,3 +152,14 @@ class ConfigContextModelQuerySet(RestrictedQuerySet): ) return base_query + + +class ObjectChangeManager(Manager.from_queryset(RestrictedQuerySet)): + + def get_queryset(self): + # Exclude any change records which refer to an instance of a model that's no longer installed. This + # can happen when a plugin is removed but its data remains in the database, for example. + app_labels = [ + app.split('.')[-1] for app in settings.INSTALLED_APPS + ] + return super().get_queryset().filter(changed_object_type__app_label__in=app_labels)