Repository: netbox-community/netbox

Issue:
Connections - Cables - Create and Add Another Error
### NetBox version

v3.5.1

### Python version

3.8

### Steps to Reproduce

1. From a Devices -> Interfaces list, click the add a cable icon.
2. Click Interface at the menu prompt
3. Fill out the form to connect cable to another interface.
4. Click Create and Add Another.

### Expected Behavior

The cable should have been created and a new form loaded to create an additional cable.

### Observed Behavior

```
Traceback (most recent call last):
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 56, in inner
    response = get_response(request)
  File "/opt/netbox/venv/lib/python3.8/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.8/site-packages/django/views/generic/base.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
  File "/opt/netbox/netbox/dcim/views.py", line 3089, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/opt/netbox/netbox/netbox/views/generic/object_views.py", line 167, 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 99, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/views/generic/base.py", line 142, in dispatch
    return handler(request, *args, **kwargs)
  File "/opt/netbox/netbox/netbox/views/generic/object_views.py", line 227, in get
    return render(request, self.template_name, {
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/shortcuts.py", line 24, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 175, in render
    return self._render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/test/utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 157, in render
    return compiled_parent._render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/test/utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 157, in render
    return compiled_parent._render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/test/utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 157, in render
    return compiled_parent._render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/test/utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 63, in render
    result = block.nodelist.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 63, in render
    result = block.nodelist.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 63, in render
    result = block.nodelist.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 1005, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/base.py", line 966, in render_annotated
    return self.render(context)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/template/library.py", line 258, in render
    _dict = self.func(*resolved_args, **resolved_kwargs)
  File "/opt/netbox/netbox/utilities/templatetags/form_helpers.py", line 55, in render_field
    'label': label or field.label,
```


Discussion:
Hey @arthanson, just wanted to see if you were on this? Just ran into this myself and was about to launch into it.

Was going to suggest as well - could we take the approach of allowing a blank form and adding cables to be added straight from the navmenu? I see value in that too - but I don't know what precedent has been set with that.

Quicker replication steps:
1. Visit https://demo.netbox.dev/dcim/cables/add/
Same error reproduced  on 3.5.2
Same error reproduced on 3.5.4. Below my proposal to fix this issue :

```python
diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py
--- a/netbox/dcim/views.py
+++ b/netbox/dcim/views.py
@@ -8,7 +8,7 @@ from django.db.models import Prefetch
 from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, modelformset_factory
 from django.http import HttpResponse
 from django.shortcuts import get_object_or_404, redirect, render
-from django.urls import reverse
+from django.urls import reverse, resolve
 from django.utils.html import escape
 from django.utils.safestring import mark_safe
 from django.utils.translation import gettext as _
@@ -3141,6 +3141,13 @@ class CableEditView(generic.ObjectEditView):

         return obj

+    def get_extra_addanother_params(self, request):
+        return {
+            'termination_a_device': resolve(request.GET.get('return_url')).kwargs.get('pk'),
+            'a_terminations_type': request.GET.get('a_terminations_type'),
+            'b_terminations_type': request.GET.get('b_terminations_type')
+        }
+

 @register_model_view(Cable, 'delete')
 class CableDeleteView(generic.ObjectDeleteView):
```

Hope this can help...
@netopsab Would you like to submit the PR?
Hi @DanSheps, why not... 


Resolving patch:
diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py
--- a/netbox/dcim/views.py
+++ b/netbox/dcim/views.py
@@ -3131,6 +3131,19 @@ def get_object(self, **kwargs):
 
         return obj
 
+    def get_extra_addanother_params(self, request):
+
+        params = {
+            'a_terminations_type': request.GET.get('a_terminations_type'),
+            'b_terminations_type': request.GET.get('b_terminations_type')
+        }
+
+        for key in request.POST:
+            if 'device' in key or 'power_panel' in key or 'circuit' in key:
+                params.update({key: request.POST.get(key)})
+
+        return params
+
 
 @register_model_view(Cable, 'delete')
 class CableDeleteView(generic.ObjectDeleteView):


Test patch: