Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion netbox/extras/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ class ObjectChangeViewSet(ReadOnlyModelViewSet):
Retrieve a list of recent changes.
"""
metadata_class = ContentTypeMetadata
queryset = ObjectChange.objects.prefetch_related('user')
queryset = ObjectChange.objects.valid_models().prefetch_related('user')
serializer_class = serializers.ObjectChangeSerializer
filterset_class = filtersets.ObjectChangeFilterSet

Expand Down
4 changes: 2 additions & 2 deletions netbox/extras/models/change_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.urls import reverse

from extras.choices import *
from utilities.querysets import RestrictedQuerySet
from ..querysets import ObjectChangeQuerySet

__all__ = (
'ObjectChange',
Expand Down Expand Up @@ -82,7 +82,7 @@ class ObjectChange(models.Model):
null=True
)

objects = RestrictedQuerySet.as_manager()
objects = ObjectChangeQuerySet.as_manager()

class Meta:
ordering = ['-time']
Expand Down
13 changes: 13 additions & 0 deletions netbox/extras/querysets.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.apps import apps
from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.aggregates import JSONBAgg
from django.db.models import OuterRef, Subquery, Q

Expand Down Expand Up @@ -151,3 +153,14 @@ def _get_config_context_filters(self):
)

return base_query


class ObjectChangeQuerySet(RestrictedQuerySet):

def valid_models(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.
content_type_ids = set(
ct.pk for ct in ContentType.objects.get_for_models(*apps.get_models()).values()
)
return self.filter(changed_object_type_id__in=content_type_ids)
3 changes: 2 additions & 1 deletion netbox/extras/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

from core.choices import ManagedFileRootPathChoices
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Rack, Location, RackRole, Site
from extras.api.views import ReportViewSet, ScriptViewSet
from extras.models import *
from extras.reports import Report
from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
Expand Down Expand Up @@ -579,6 +578,7 @@ def setUp(self):
super().setUp()

# Monkey-patch the API viewset's _get_report() method to return our test Report above
from extras.api.views import ReportViewSet
ReportViewSet._get_report = self.get_test_report

def test_get_report(self):
Expand Down Expand Up @@ -621,6 +621,7 @@ def setUp(self):
super().setUp()

# Monkey-patch the API viewset's _get_script() method to return our test Script above
from extras.api.views import ScriptViewSet
ScriptViewSet._get_script = self.get_test_script

def test_get_script(self):
Expand Down
8 changes: 4 additions & 4 deletions netbox/extras/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ class ConfigTemplateBulkSyncDataView(generic.BulkSyncDataView):
#

class ObjectChangeListView(generic.ObjectListView):
queryset = ObjectChange.objects.all()
queryset = ObjectChange.objects.valid_models()
filterset = filtersets.ObjectChangeFilterSet
filterset_form = forms.ObjectChangeFilterForm
table = tables.ObjectChangeTable
Expand All @@ -521,10 +521,10 @@ class ObjectChangeListView(generic.ObjectListView):

@register_model_view(ObjectChange)
class ObjectChangeView(generic.ObjectView):
queryset = ObjectChange.objects.all()
queryset = ObjectChange.objects.valid_models()

def get_extra_context(self, request, instance):
related_changes = ObjectChange.objects.restrict(request.user, 'view').filter(
related_changes = ObjectChange.objects.valid_models().restrict(request.user, 'view').filter(
request_id=instance.request_id
).exclude(
pk=instance.pk
Expand All @@ -534,7 +534,7 @@ def get_extra_context(self, request, instance):
orderable=False
)

objectchanges = ObjectChange.objects.restrict(request.user, 'view').filter(
objectchanges = ObjectChange.objects.valid_models().restrict(request.user, 'view').filter(
changed_object_type=instance.changed_object_type,
changed_object_id=instance.changed_object_id,
)
Expand Down
4 changes: 3 additions & 1 deletion netbox/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ class ProfileView(LoginRequiredMixin, View):
def get(self, request):

# Compile changelog table
changelog = ObjectChange.objects.restrict(request.user, 'view').filter(user=request.user).prefetch_related(
changelog = ObjectChange.objects.valid_models().restrict(request.user, 'view').filter(
user=request.user
).prefetch_related(
'changed_object_type'
)[:20]
changelog_table = ObjectChangeTable(changelog)
Expand Down