Просмотр исходного кода

#2434: Refactor ComponentCreateView to use generic form validation method

New validate_form method on ComponentCreateView handles validation generically, which any post() method on ComponentCreateView can use to validate the form but handle the response differently as needed.
checktheroads 4 лет назад
Родитель
Сommit
2d2719cfb2
2 измененных файлов с 38 добавлено и 72 удалено
  1. 12 55
      netbox/dcim/views.py
  2. 26 17
      netbox/netbox/views/generic.py

+ 12 - 55
netbox/dcim/views.py

@@ -1914,65 +1914,22 @@ class InterfaceCreateView(generic.ComponentCreateView):
     template_name = 'dcim/device_component_add.html'
 
     def post(self, request):
+        """
+        Override inherited post() method to handle request to assign newly created
+        interface objects (first object) to an IP Address object.
+        """
         logger = logging.getLogger('netbox.dcim.views.InterfaceCreateView')
         form = self.form(request.POST, initial=request.GET)
+        self.validate_form(request, form)
 
         if form.is_valid():
-
-            new_components = []
-            data = deepcopy(request.POST)
-
-            names = form.cleaned_data['name_pattern']
-            labels = form.cleaned_data.get('label_pattern')
-            for i, name in enumerate(names):
-                label = labels[i] if labels else None
-                # Initialize the individual component form
-                data['name'] = name
-                data['label'] = label
-                if hasattr(form, 'get_iterative_data'):
-                    data.update(form.get_iterative_data(i))
-                component_form = self.model_form(data)
-
-                if component_form.is_valid():
-                    new_components.append(component_form)
-                else:
-                    for field, errors in component_form.errors.as_data().items():
-                        # Assign errors on the child form's name/label field to name_pattern/label_pattern on the parent form
-                        if field == 'name':
-                            field = 'name_pattern'
-                        elif field == 'label':
-                            field = 'label_pattern'
-                        for e in errors:
-                            form.add_error(field, '{}: {}'.format(name, ', '.join(e)))
-
-            if not form.errors:
-                try:
-                    # Create the new components
-                    new_objs = []
-                    with transaction.atomic():
-                        for component_form in new_components:
-                            obj = component_form.save()
-                            new_objs.append(obj)
-
-                        # Enforce object-level permissions
-                        if self.queryset.filter(pk__in=[obj.pk for obj in new_objs]).count() != len(new_objs):
-                            raise ObjectDoesNotExist
-
-                    messages.success(request, "Added {} {}".format(
-                        len(new_components), self.queryset.model._meta.verbose_name_plural
-                    ))
-                    if '_addanother' in request.POST:
-                        return redirect(request.get_full_path())
-                    elif '_assignip' in request.POST and len(new_objs) >= 1 and request.user.has_perm('ipam.add_ipaddress'):
-                        first_obj = new_objs[0].pk
-                        return redirect(f'/ipam/ip-addresses/add/?interface={first_obj}&return_url={self.get_return_url(request)}')
-                    else:
-                        return redirect(self.get_return_url(request))
-
-                except ObjectDoesNotExist:
-                    msg = "Component creation failed due to object-level permissions violation"
-                    logger.debug(msg)
-                    form.add_error(None, msg)
+            if '_addanother' in request.POST:
+                return redirect(request.get_full_path())
+            elif '_assignip' in request.POST and len(self.created_objects) >= 1 and request.user.has_perm('ipam.add_ipaddress'):
+                first_obj = self.created_objects[0].pk
+                return redirect(f'/ipam/ip-addresses/add/?interface={first_obj}&return_url={self.get_return_url(request)}')
+            else:
+                return redirect(self.get_return_url(request))
 
         return render(request, self.template_name, {
             'component_type': self.queryset.model._meta.verbose_name,

+ 26 - 17
netbox/netbox/views/generic.py

@@ -1088,6 +1088,7 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View
     form = None
     model_form = None
     template_name = None
+    created_objects = []
 
     def get_required_permission(self):
         return get_permission_for_model(self.queryset.model, 'add')
@@ -1105,25 +1106,47 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View
     def post(self, request):
         logger = logging.getLogger('netbox.views.ComponentCreateView')
         form = self.form(request.POST, initial=request.GET)
+        self.validate_form(request, form)
 
         if form.is_valid():
+            if '_addanother' in request.POST:
+                return redirect(request.get_full_path())
+            else:
+                return redirect(self.get_return_url(request))
+
+        return render(request, self.template_name, {
+            'component_type': self.queryset.model._meta.verbose_name,
+            'form': form,
+            'return_url': self.get_return_url(request),
+        })
 
+    def validate_form(self, request, form):
+        """
+        Validate form values and set errors on the form object as they are detected. If
+        no errors are found, signal success messages.
+        """
+
+        logger = logging.getLogger('netbox.views.ComponentCreateView')
+        if form.is_valid():
             new_components = []
             data = deepcopy(request.POST)
-
             names = form.cleaned_data['name_pattern']
             labels = form.cleaned_data.get('label_pattern')
+
             for i, name in enumerate(names):
                 label = labels[i] if labels else None
                 # Initialize the individual component form
                 data['name'] = name
                 data['label'] = label
+
                 if hasattr(form, 'get_iterative_data'):
                     data.update(form.get_iterative_data(i))
+
                 component_form = self.model_form(data)
 
                 if component_form.is_valid():
                     new_components.append(component_form)
+
                 else:
                     for field, errors in component_form.errors.as_data().items():
                         # Assign errors on the child form's name/label field to name_pattern/label_pattern on the parent form
@@ -1135,40 +1158,26 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View
                             form.add_error(field, '{}: {}'.format(name, ', '.join(e)))
 
             if not form.errors:
-
                 try:
-
                     with transaction.atomic():
-
                         # Create the new components
-                        new_objs = []
                         for component_form in new_components:
                             obj = component_form.save()
-                            new_objs.append(obj)
+                            self.created_objects.append(obj)
 
                         # Enforce object-level permissions
-                        if self.queryset.filter(pk__in=[obj.pk for obj in new_objs]).count() != len(new_objs):
+                        if self.queryset.filter(pk__in=[obj.pk for obj in self.created_objects]).count() != len(self.created_objects):
                             raise ObjectDoesNotExist
 
                     messages.success(request, "Added {} {}".format(
                         len(new_components), self.queryset.model._meta.verbose_name_plural
                     ))
-                    if '_addanother' in request.POST:
-                        return redirect(request.get_full_path())
-                    else:
-                        return redirect(self.get_return_url(request))
 
                 except ObjectDoesNotExist:
                     msg = "Component creation failed due to object-level permissions violation"
                     logger.debug(msg)
                     form.add_error(None, msg)
 
-        return render(request, self.template_name, {
-            'component_type': self.queryset.model._meta.verbose_name,
-            'form': form,
-            'return_url': self.get_return_url(request),
-        })
-
 
 class BulkComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
     """