mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-09 01:49:35 -06:00
Fixes #20641: Handle viewsets with queryset=None in get_view_name() (#20642)
Some checks are pending
CI / build (20.x, 3.10) (push) Waiting to run
CI / build (20.x, 3.11) (push) Waiting to run
CI / build (20.x, 3.12) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, actions) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Waiting to run
Some checks are pending
CI / build (20.x, 3.10) (push) Waiting to run
CI / build (20.x, 3.11) (push) Waiting to run
CI / build (20.x, 3.12) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, actions) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Waiting to run
The get_view_name() utility function crashed with AttributeError when called on viewsets that override get_queryset() without setting a class-level queryset attribute (e.g., ObjectChangeViewSet). This pattern became necessary in #20089 to force re-evaluation of valid_models() on each request, ensuring ObjectChange querysets reflect current ContentType state. Added None check to fall back to DRF's default view naming when no class-level queryset exists.
This commit is contained in:
parent
ae5d7911f9
commit
fb8d41b527
@ -72,7 +72,7 @@ def get_view_name(view):
|
||||
Derive the view name from its associated model, if it has one. Fall back to DRF's built-in `get_view_name()`.
|
||||
This function is provided to DRF as its VIEW_NAME_FUNCTION.
|
||||
"""
|
||||
if hasattr(view, 'queryset'):
|
||||
if hasattr(view, 'queryset') and view.queryset is not None:
|
||||
# Derive the model name from the queryset.
|
||||
name = title(view.queryset.model._meta.verbose_name)
|
||||
if suffix := getattr(view, 'suffix', None):
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from django.test import Client, TestCase, override_settings
|
||||
from django.test import Client, TestCase, override_settings, tag
|
||||
from django.urls import reverse
|
||||
from drf_spectacular.drainage import GENERATOR_STATS
|
||||
from rest_framework import status
|
||||
@ -9,6 +9,7 @@ from extras.choices import CustomFieldTypeChoices
|
||||
from extras.models import CustomField
|
||||
from ipam.models import VLAN
|
||||
from netbox.config import get_config
|
||||
from utilities.api import get_view_name
|
||||
from utilities.testing import APITestCase, disable_warnings
|
||||
|
||||
|
||||
@ -267,3 +268,19 @@ class APIDocsTestCase(TestCase):
|
||||
with GENERATOR_STATS.silence(): # Suppress schema generator warnings
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class GetViewNameTestCase(TestCase):
|
||||
|
||||
@tag('regression')
|
||||
def test_get_view_name_with_none_queryset(self):
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||
|
||||
class MockViewSet(ReadOnlyModelViewSet):
|
||||
queryset = None
|
||||
|
||||
view = MockViewSet()
|
||||
view.suffix = 'List'
|
||||
|
||||
name = get_view_name(view)
|
||||
self.assertEqual(name, 'Mock List')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user