diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a56c967b..fd64207ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ v2.5.3 (FUTURE) * [#1630](https://github.com/digitalocean/netbox/issues/1630) - Enable bulk editing of prefix/IP mask length * [#1870](https://github.com/digitalocean/netbox/issues/1870) - Add per-page toggle to object lists * [#1871](https://github.com/digitalocean/netbox/issues/1871) - Enable filtering sites by parent region +* [#1983](https://github.com/digitalocean/netbox/issues/1983) - Enable regular expressions when bulk renaming device components * [#2693](https://github.com/digitalocean/netbox/issues/2693) - Additional cable colors * [#2726](https://github.com/digitalocean/netbox/issues/2726) - Include cables in global search diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index c15952330..887e7f74f 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -58,6 +58,22 @@ class BulkRenameForm(forms.Form): """ find = forms.CharField() replace = forms.CharField() + use_regex = forms.BooleanField( + required=False, + initial=True, + label='Use regular expressions' + ) + + def clean(self): + + # Validate regular expression in "find" field + if self.cleaned_data['use_regex']: + try: + re.compile(self.cleaned_data['find']) + except re.error: + raise forms.ValidationError({ + 'find': "Invalid regular expression" + }) # diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 93a5178f3..4c2dee5df 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -1,3 +1,5 @@ +import re + from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.paginator import EmptyPage, PageNotAnInteger @@ -50,7 +52,16 @@ class BulkRenameView(GetReturnURLMixin, View): if form.is_valid(): for obj in selected_objects: - obj.new_name = obj.name.replace(form.cleaned_data['find'], form.cleaned_data['replace']) + find = form.cleaned_data['find'] + replace = form.cleaned_data['replace'] + if form.cleaned_data['use_regex']: + try: + obj.new_name = re.sub(find, replace, obj.name) + # Catch regex group reference errors + except re.error: + obj.new_name = obj.name + else: + obj.new_name = obj.name.replace(find, replace) if '_apply' in request.POST: for obj in selected_objects: