2
0
Эх сурвалжийг харах

Merge pull request #21762 from netbox-community/20162-background

#20162 allow background job when adding components to devices in bulk
bctiemann 2 өдөр өмнө
parent
commit
74aa822b27

+ 2 - 1
netbox/dcim/forms/bulk_create.py

@@ -6,6 +6,7 @@ from extras.models import Tag
 from netbox.forms.mixins import CustomFieldsMixin
 from utilities.forms import form_from_model
 from utilities.forms.fields import DynamicModelMultipleChoiceField, ExpandableNameField
+from utilities.forms.mixins import BackgroundJobMixin
 
 from .object_create import ComponentCreateForm
 
@@ -27,7 +28,7 @@ __all__ = (
 # Device components
 #
 
-class DeviceBulkAddComponentForm(CustomFieldsMixin, ComponentCreateForm):
+class DeviceBulkAddComponentForm(BackgroundJobMixin, CustomFieldsMixin, ComponentCreateForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=Device.objects.all(),
         widget=forms.MultipleHiddenInput()

+ 31 - 6
netbox/netbox/views/generic/bulk_views.py

@@ -1137,8 +1137,18 @@ class BulkComponentCreateView(GetReturnURLMixin, BaseMultiObjectView):
             if form.is_valid():
                 logger.debug("Form validation was successful")
 
+                # If indicated, defer this request to a background job & redirect the user
+                if form.cleaned_data['background_job']:
+                    job_name = _('Bulk add {count} {object_type}').format(
+                        count=len(form.cleaned_data['pk']),
+                        object_type=self.queryset.model._meta.verbose_name_plural,
+                    )
+                    if process_request_as_job(self.__class__, request, name=job_name):
+                        return redirect(self.get_return_url(request))
+
                 new_components = []
                 data = deepcopy(form.cleaned_data)
+                data.pop('background_job', None)
                 replication_data = {
                     field: data.pop(field) for field in form.replication_fields
                 }
@@ -1166,7 +1176,10 @@ class BulkComponentCreateView(GetReturnURLMixin, BaseMultiObjectView):
                                 else:
                                     for field, errors in component_form.errors.as_data().items():
                                         for e in errors:
-                                            form.add_error(field, '{}: {}'.format(obj, ', '.join(e)))
+                                            err_msg = '{}: {}'.format(obj, ', '.join(e))
+                                            form.add_error(field, err_msg)
+                                            if is_background_request(request):
+                                                request.job.logger.error(err_msg)
 
                         # Enforce object-level permissions
                         component_ids = [obj.pk for obj in new_components]
@@ -1175,20 +1188,32 @@ class BulkComponentCreateView(GetReturnURLMixin, BaseMultiObjectView):
 
                 except IntegrityError:
                     clear_events.send(sender=self)
+                    if is_background_request(request):
+                        request.job.logger.error(_("An integrity error occurred while creating components"))
+                        raise JobFailed
 
                 except (AbortRequest, PermissionsViolation) as e:
                     logger.debug(e.message)
                     form.add_error(None, e.message)
                     clear_events.send(sender=self)
+                    if is_background_request(request):
+                        request.job.logger.error(e.message)
+                        raise JobFailed
 
                 if not form.errors:
-                    msg = "Added {} {} to {} {}.".format(
-                        len(new_components),
-                        model_name,
-                        len(form.cleaned_data['pk']),
-                        parent_model_name
+                    msg = _("Added {count} {component} to {parent_count} {parent}.").format(
+                        count=len(new_components),
+                        component=model_name,
+                        parent_count=len(form.cleaned_data['pk']),
+                        parent=parent_model_name,
                     )
                     logger.info(msg)
+
+                    # Handle background job
+                    if is_background_request(request):
+                        request.job.logger.info(msg)
+                        return None
+
                     messages.success(request, msg)
 
                     return redirect(self.get_return_url(request))

+ 9 - 1
netbox/templates/generic/bulk_add_component.html

@@ -58,10 +58,18 @@ Context:
             <h2 class="card-header">{{ model_name|title }} {% trans "to Add" %}</h2>
             <div class="card-body">
               {% for field in form.visible_fields %}
-                {% render_field field %}
+                {% if not form.meta_fields or field.name not in form.meta_fields %}
+                  {% render_field field %}
+                {% endif %}
               {% endfor %}
             </div>
           </div>
+          {# Meta fields #}
+          {% if form.background_job %}
+          <div class="bg-primary-subtle border border-primary rounded-1 pt-3 px-3 mb-3">
+            {% render_field form.background_job %}
+          </div>
+          {% endif %}
           <div class="form-group text-end">
             <div class="col col-md-12">
               <a href="{{ return_url }}" class="btn btn-outline-secondary">{% trans "Cancel" %}</a>

+ 2 - 1
netbox/virtualization/forms/bulk_create.py

@@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _
 
 from utilities.forms import form_from_model
 from utilities.forms.fields import ExpandableNameField
+from utilities.forms.mixins import BackgroundJobMixin
 from virtualization.models import VirtualDisk, VirtualMachine, VMInterface
 
 __all__ = (
@@ -11,7 +12,7 @@ __all__ = (
 )
 
 
-class VirtualMachineBulkAddComponentForm(forms.Form):
+class VirtualMachineBulkAddComponentForm(BackgroundJobMixin, forms.Form):
     pk = forms.ModelMultipleChoiceField(
         queryset=VirtualMachine.objects.all(),
         widget=forms.MultipleHiddenInput()