NoReverseMatch exceptions for plugins without REST API
Deployment Type
Self-hosted
Triage priority
I volunteer to perform this work (if approved)
NetBox Version
v4.1.3
Python Version
3.11
Steps to Reproduce
- Install a NetBox plugin.
- Remove API URLs by replacing
api/urls.pyby this code:from netbox.api.routers import NetBoxRouter router = NetBoxRouter() urlpatterns = router.urls - Edit a model of the plugin via UI and save.
Expected Behavior
- Model changes will be saved to the database.
- REST API for this plugin is not available. According to the documentation this should be valid behavior, as it's just a "can".
Observed Behavior
An exception is raised.
Traceback (most recent call last):
File "/opt/netbox/venv/lib/python3.12/site-packages/rest_framework/relations.py", line 396, in to_representation
url = self.get_url(value, self.view_name, request, format)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/netbox/api/serializers/fields.py", line 37, in get_url
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/rest_framework/reverse.py", line 47, in reverse
url = _reverse(viewname, args, kwargs, request, format, **extra)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/rest_framework/reverse.py", line 60, in _reverse
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/urls/base.py", line 88, in reverse
return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 851, in _reverse_with_prefix
raise NoReverseMatch(msg)
^^^^^^^^^^^^^^^^^^^^^^^^^
During handling of the above exception (Reverse for 'domainlistentry-detail' not found. 'domainlistentry-detail' is not a valid view function or pattern name.), another exception occurred:
File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/views/generic/base.py", line 104, in view
return self.dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/netbox/views/generic/object_views.py", line 182, in dispatch
return super().dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/netbox/views/generic/base.py", line 26, in dispatch
return super().dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/utilities/views.py", line 125, in dispatch
return super().dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/utilities/views.py", line 39, in dispatch
return super().dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/views/generic/base.py", line 143, in dispatch
return handler(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/netbox/views/generic/object_views.py", line 278, in post
obj = form.save()
^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/forms/models.py", line 552, in save
self.instance.save()
^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/models/base.py", line 822, in save
self.save_base(
^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/models/base.py", line 924, in save_base
post_save.send(
^
File "/opt/netbox/venv/lib/python3.12/site-packages/django/dispatch/dispatcher.py", line 189, in send
response = receiver(signal=self, sender=sender, **named)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/core/signals.py", line 102, in handle_changed_object
enqueue_event(queue, instance, request.user, request.id, event_type)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/extras/events.py", line 77, in enqueue_event
'data': serialize_for_event(instance),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/netbox/extras/events.py", line 35, in serialize_for_event
return serializer.data
^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/rest_framework/serializers.py", line 571, in data
ret = super().data
^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/rest_framework/serializers.py", line 249, in data
self._data = self.to_representation(self.instance)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/rest_framework/serializers.py", line 538, in to_representation
ret[field.field_name] = field.to_representation(attribute)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/netbox/venv/lib/python3.12/site-packages/rest_framework/relations.py", line 411, in to_representation
raise ImproperlyConfigured(msg % self.view_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Exception Type: ImproperlyConfigured at /plugins/blocklists/domain/lists/entries/add/
Exception Value: Could not resolve URL for hyperlinked relationship using view name "". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
I believe I can track this down to #15156, where the serializers got automatic URL lookup. The new BaseNetBoxHyperlinkedIdentityField.get_url() method even states:
May raise a
NoReverseMatchif theview_nameandlookup_fieldattributes are not configured to correctly match the URL conf.
To solve this easily, I suggest to change the documentation. The serializers are indeed required for NetBox to work properly. However, if someone doesn't want to provide the REST API (or hasn't developed it yet), it is sufficient to simply add url = None to the serializer.
The serializers are indeed required for NetBox to work properly
Maybe we could tweak serialize_for_event() to fall back to using a generic JSON serializer (i.e. serialize_object()) when a custom serializer does not exist for a model.
This would be possible. However events may require a defined set of fields that are not provided by the default serialize_object() (e.g. display). Switching the serializer could make things worse if administrators have to worry about what type of payload is being passed.
Maybe we could catch the NoReverseMatch exception in BaseNetBoxHyperlinkedIdentityField.get_url() simply returning no or an empty url if no REST API endpoint is available for this model.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. Do not attempt to circumvent this process by "bumping" the issue; doing so will result in its immediate closure and you may be barred from participating in any future discussions. Please see our contributing guide.
This issue has been automatically closed due to lack of activity. In an effort to reduce noise, please do not comment any further. Note that the core maintainers may elect to reopen this issue at a later date if deemed necessary.