Browse Source

Closes #648: Pre-populate forms when selecting "create and add another"

Jeremy Stretch 6 years ago
parent
commit
2956eff051

+ 1 - 0
docs/release-notes/version-2.7.md

@@ -128,6 +128,7 @@ PATCH) to maintain backward compatibility. This behavior will be discontinued be
 ## Enhancements
 ## Enhancements
 
 
 * [#33](https://github.com/digitalocean/netbox/issues/33) - Add ability to clone objects (pre-populate form fields)
 * [#33](https://github.com/digitalocean/netbox/issues/33) - Add ability to clone objects (pre-populate form fields)
+* [#648](https://github.com/digitalocean/netbox/issues/648) - Pre-populate forms when selecting "create and add another"
 * [#792](https://github.com/digitalocean/netbox/issues/792) - Add power port and power outlet types
 * [#792](https://github.com/digitalocean/netbox/issues/792) - Add power port and power outlet types
 * [#1865](https://github.com/digitalocean/netbox/issues/1865) - Add console port and console server port types
 * [#1865](https://github.com/digitalocean/netbox/issues/1865) - Add console port and console server port types
 * [#2902](https://github.com/digitalocean/netbox/issues/2902) - Replace `supervisord` with `systemd`
 * [#2902](https://github.com/digitalocean/netbox/issues/2902) - Replace `supervisord` with `systemd`

+ 2 - 21
netbox/utilities/templatetags/buttons.py

@@ -2,6 +2,7 @@ from django import template
 from django.urls import reverse
 from django.urls import reverse
 
 
 from extras.models import ExportTemplate
 from extras.models import ExportTemplate
+from utilities.utils import prepare_cloned_fields
 
 
 register = template.Library()
 register = template.Library()
 
 
@@ -24,27 +25,7 @@ def import_button(url):
 def clone_button(url, instance):
 def clone_button(url, instance):
 
 
     url = reverse(url)
     url = reverse(url)
-
-    # Populate form field values
-    params = {}
-    for field_name in getattr(instance, 'clone_fields', []):
-        field = instance._meta.get_field(field_name)
-        field_value = field.value_from_object(instance)
-
-        # Swap out False with URL-friendly value
-        if field_value is False:
-            field_value = ''
-
-        # Omit empty values
-        if field_value not in (None, ''):
-            params[field_name] = field_value
-
-        # Copy tags
-        if hasattr(instance, 'tags'):
-            params['tags'] = ','.join([t.name for t in instance.tags.all()])
-
-    # Append parameters to URL
-    param_string = '&'.join(['{}={}'.format(k, v) for k, v in params.items()])
+    param_string = prepare_cloned_fields(instance)
     if param_string:
     if param_string:
         url = '{}?{}'.format(url, param_string)
         url = '{}?{}'.format(url, param_string)
 
 

+ 30 - 0
netbox/utilities/utils.py

@@ -180,3 +180,33 @@ def to_meters(length, unit):
         return length * 0.3048
         return length * 0.3048
     if unit == CableLengthUnitChoices.UNIT_INCH:
     if unit == CableLengthUnitChoices.UNIT_INCH:
         return length * 0.3048 * 12
         return length * 0.3048 * 12
+
+
+def prepare_cloned_fields(instance):
+    """
+    Compile an object's `clone_fields` list into a string of URL query parameters. Tags are automatically cloned where
+    applicable.
+    """
+    params = {}
+    for field_name in getattr(instance, 'clone_fields', []):
+        field = instance._meta.get_field(field_name)
+        field_value = field.value_from_object(instance)
+
+        # Swap out False with URL-friendly value
+        if field_value is False:
+            field_value = ''
+
+        # Omit empty values
+        if field_value not in (None, ''):
+            params[field_name] = field_value
+
+        # Copy tags
+        if hasattr(instance, 'tags'):
+            params['tags'] = ','.join([t.name for t in instance.tags.all()])
+
+    # Concatenate parameters into a URL query string
+    param_string = '&'.join(
+        ['{}={}'.format(k, v) for k, v in params.items()]
+    )
+
+    return param_string

+ 7 - 3
netbox/utilities/views.py

@@ -1,6 +1,4 @@
-import json
 import sys
 import sys
-import yaml
 from copy import deepcopy
 from copy import deepcopy
 
 
 from django.conf import settings
 from django.conf import settings
@@ -28,7 +26,7 @@ from extras.models import CustomField, CustomFieldValue, ExportTemplate
 from extras.querysets import CustomFieldQueryset
 from extras.querysets import CustomFieldQueryset
 from utilities.exceptions import AbortTransaction
 from utilities.exceptions import AbortTransaction
 from utilities.forms import BootstrapMixin, CSVDataField
 from utilities.forms import BootstrapMixin, CSVDataField
-from utilities.utils import csv_format
+from utilities.utils import csv_format, prepare_cloned_fields
 from .error_handlers import handle_protectederror
 from .error_handlers import handle_protectederror
 from .forms import ConfirmationForm, ImportForm
 from .forms import ConfirmationForm, ImportForm
 from .paginator import EnhancedPaginator
 from .paginator import EnhancedPaginator
@@ -238,6 +236,12 @@ class ObjectEditView(GetReturnURLMixin, View):
             messages.success(request, mark_safe(msg))
             messages.success(request, mark_safe(msg))
 
 
             if '_addanother' in request.POST:
             if '_addanother' in request.POST:
+
+                # If the object has clone_fields, pre-populate a new instance of the form
+                if hasattr(obj, 'clone_fields'):
+                    url = '{}?{}'.format(request.path, prepare_cloned_fields(obj))
+                    return redirect(url)
+
                 return redirect(request.get_full_path())
                 return redirect(request.get_full_path())
 
 
             return_url = form.cleaned_data.get('return_url')
             return_url = form.cleaned_data.get('return_url')