Repository: netbox-community/netbox

Issue:
Device "Create and Add Another" does not retain Manufacturer and Device Type
### Environment
* Python version: 3.5.2
* NetBox version:  2.7.1

### Steps to Reproduce
1. Add Device
2. Enter Name, Role, Manufacturer, Device Type, Site and Rack (optionally Tags and Comments)
3. Click "Create and Add Another"

### Expected Behavior

Given the new feature in 2.7, I was expecting the fields to be carried forward into the next form.

### Observed Behavior

Manufacturer and Device Type are *not* carried forward (neither are Comments)

However: Role, Site, Rack and Tags *are* carried forward.


Discussion:
This is a bug with the form widgets. We're passing an initial value for the `device_type` field, however that field is chained to `manufacturer`, which has no initial value, so the set of available choices for `device_type` is empty.
@jeremystretch checkout #3912 as it removes chaining (no longer needed, explanation in the ticket). It's also the cause of the issue you noticed in https://github.com/netbox-community/netbox/pull/3893#discussion_r365908986.

Resolving patch:
diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py
--- a/netbox/dcim/forms.py
+++ b/netbox/dcim/forms.py
@@ -1642,6 +1642,16 @@ def __init__(self, *args, **kwargs):
         if instance and instance.cluster is not None:
             kwargs['initial']['cluster_group'] = instance.cluster.group
 
+        if 'device_type' in kwargs['initial'] and 'manufacturer' not in kwargs['initial']:
+            device_type_id = kwargs['initial']['device_type']
+            manufacturer_id = DeviceType.objects.filter(pk=device_type_id).values_list('manufacturer__pk', flat=True).first()
+            kwargs['initial']['manufacturer'] = manufacturer_id
+
+        if 'cluster' in kwargs['initial'] and 'cluster_group' not in kwargs['initial']:
+            cluster_id = kwargs['initial']['cluster']
+            cluster_group_id = Cluster.objects.filter(pk=cluster_id).values_list('group__pk', flat=True).first()
+            kwargs['initial']['cluster_group'] = cluster_group_id
+
         super().__init__(*args, **kwargs)
 
         if self.instance.pk:


Test patch:
diff --git a/netbox/dcim/tests/test_forms.py b/netbox/dcim/tests/test_forms.py
--- a/netbox/dcim/tests/test_forms.py
+++ b/netbox/dcim/tests/test_forms.py
@@ -10,7 +10,7 @@ def get_id(model, slug):
 
 class DeviceTestCase(TestCase):
 
-    fixtures = ['dcim', 'ipam']
+    fixtures = ['dcim', 'ipam', 'virtualization']
 
     def test_racked_device(self):
         test = DeviceForm(data={
@@ -78,3 +78,15 @@ def test_non_racked_device_with_face(self):
         })
         self.assertTrue(test.is_valid())
         self.assertTrue(test.save())
+
+    def test_cloned_cluster_device_initial_data(self):
+        test = DeviceForm(initial={
+            'device_type': get_id(DeviceType, 'poweredge-r640'),
+            'device_role': get_id(DeviceRole, 'server'),
+            'status': DeviceStatusChoices.STATUS_ACTIVE,
+            'site': get_id(Site, 'test1'),
+            "cluster": Cluster.objects.get(id=4).id,
+        })
+        self.assertEqual(test.initial['manufacturer'], get_id(Manufacturer, 'dell'))
+        self.assertIn('cluster_group', test.initial)
+        self.assertEqual(test.initial['cluster_group'], get_id(ClusterGroup, 'vm-host'))