diff --git a/docs/release-notes/version-2.7.md b/docs/release-notes/version-2.7.md index 4e70f73a780..bf25eb3f1bf 100644 --- a/docs/release-notes/version-2.7.md +++ b/docs/release-notes/version-2.7.md @@ -128,6 +128,7 @@ PATCH) to maintain backward compatibility. This behavior will be discontinued be ## Enhancements * [#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 * [#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` diff --git a/netbox/utilities/templatetags/buttons.py b/netbox/utilities/templatetags/buttons.py index 45323d5cdb6..8e836f6856e 100644 --- a/netbox/utilities/templatetags/buttons.py +++ b/netbox/utilities/templatetags/buttons.py @@ -2,6 +2,7 @@ from django.urls import reverse from extras.models import ExportTemplate +from utilities.utils import prepare_cloned_fields register = template.Library() @@ -24,27 +25,7 @@ def import_button(url): def clone_button(url, instance): 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: url = '{}?{}'.format(url, param_string) diff --git a/netbox/utilities/utils.py b/netbox/utilities/utils.py index 3720fd76d1e..4837cb5b499 100644 --- a/netbox/utilities/utils.py +++ b/netbox/utilities/utils.py @@ -180,3 +180,33 @@ def to_meters(length, unit): return length * 0.3048 if unit == CableLengthUnitChoices.UNIT_INCH: 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 diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index 48c4f01e66d..5631a6ec655 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -1,6 +1,4 @@ -import json import sys -import yaml from copy import deepcopy from django.conf import settings @@ -28,7 +26,7 @@ from extras.querysets import CustomFieldQueryset from utilities.exceptions import AbortTransaction 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 .forms import ConfirmationForm, ImportForm from .paginator import EnhancedPaginator @@ -238,6 +236,12 @@ def post(self, request, *args, **kwargs): messages.success(request, mark_safe(msg)) 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_url = form.cleaned_data.get('return_url')