Parcourir la source

Allow import/export of device types (#1347)

Faidon Liambotis il y a 8 ans
Parent
commit
4544893b4c

+ 32 - 1
netbox/dcim/forms.py

@@ -24,7 +24,7 @@ from .models import (
     IFACE_FF_CHOICES, IFACE_FF_LAG, IFACE_ORDERING_CHOICES, InterfaceConnection, InterfaceTemplate, Manufacturer,
     InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, RACK_FACE_CHOICES,
     RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, Rack, RackGroup, RackReservation, RackRole, RACK_WIDTH_19IN, RACK_WIDTH_23IN,
-    Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT,
+    Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT, SUBDEVICE_ROLE_CHOICES,
 )
 
 
@@ -451,6 +451,37 @@ class DeviceTypeForm(BootstrapMixin, CustomFieldForm):
         }
 
 
+class DeviceTypeCSVForm(forms.ModelForm):
+    manufacturer = forms.ModelChoiceField(
+        queryset=Manufacturer.objects.all(),
+        required=True,
+        to_field_name='name',
+        help_text='Manufacturer name',
+        error_messages={
+            'invalid_choice': 'Manufacturer not found.',
+        }
+    )
+    subdevice_role = CSVChoiceField(
+        choices=SUBDEVICE_ROLE_CHOICES,
+        required=False,
+        help_text='Parent/child status'
+    )
+    interface_ordering = CSVChoiceField(
+        choices=IFACE_ORDERING_CHOICES,
+        required=False,
+        help_text='Interface ordering'
+    )
+
+    class Meta:
+        model = DeviceType
+        fields = ['manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server',
+                  'is_pdu', 'is_network_device', 'subdevice_role', 'interface_ordering', 'comments']
+        help_texts = {
+            'model': 'Model name',
+            'slug': 'URL-friendly slug',
+        }
+
+
 class DeviceTypeBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
     pk = forms.ModelMultipleChoiceField(queryset=DeviceType.objects.all(), widget=forms.MultipleHiddenInput)
     manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(), required=False)

+ 20 - 0
netbox/dcim/models.py

@@ -513,6 +513,11 @@ class DeviceType(models.Model, CustomFieldModel):
     comments = models.TextField(blank=True)
     custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id')
 
+    csv_headers = [
+        'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server',
+        'is_pdu', 'is_network_device', 'subdevice_role', 'interface_ordering',
+    ]
+
     class Meta:
         ordering = ['manufacturer', 'model']
         unique_together = [
@@ -532,6 +537,21 @@ class DeviceType(models.Model, CustomFieldModel):
     def get_absolute_url(self):
         return reverse('dcim:devicetype', args=[self.pk])
 
+    def to_csv(self):
+        return csv_format([
+            self.manufacturer.name,
+            self.model,
+            self.slug,
+            self.part_number,
+            self.u_height,
+            self.is_full_depth,
+            self.is_console_server,
+            self.is_pdu,
+            self.is_network_device,
+            self.get_subdevice_role_display() if self.subdevice_role else None,
+            self.get_interface_ordering_display(),
+        ])
+
     def clean(self):
 
         # If editing an existing DeviceType to have a larger u_height, first validate that *all* instances of it have

+ 1 - 0
netbox/dcim/urls.py

@@ -71,6 +71,7 @@ urlpatterns = [
     # Device types
     url(r'^device-types/$', views.DeviceTypeListView.as_view(), name='devicetype_list'),
     url(r'^device-types/add/$', views.DeviceTypeCreateView.as_view(), name='devicetype_add'),
+    url(r'^device-types/import/$', views.DeviceTypeBulkImportView.as_view(), name='devicetype_import'),
     url(r'^device-types/edit/$', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'),
     url(r'^device-types/delete/$', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'),
     url(r'^device-types/(?P<pk>\d+)/$', views.DeviceTypeView.as_view(), name='devicetype'),

+ 7 - 0
netbox/dcim/views.py

@@ -658,6 +658,13 @@ class DeviceTypeDeleteView(PermissionRequiredMixin, ObjectDeleteView):
     default_return_url = 'dcim:devicetype_list'
 
 
+class DeviceTypeBulkImportView(PermissionRequiredMixin, BulkImportView):
+    permission_required = 'dcim.add_devicetype'
+    model_form = forms.DeviceTypeCSVForm
+    table = tables.DeviceTypeTable
+    default_return_url = 'dcim:devicetype_list'
+
+
 class DeviceTypeBulkEditView(PermissionRequiredMixin, BulkEditView):
     permission_required = 'dcim.change_devicetype'
     cls = DeviceType

+ 1 - 1
netbox/extras/constants.py

@@ -37,7 +37,7 @@ GRAPH_TYPE_CHOICES = (
 
 # Models which support export templates
 EXPORTTEMPLATE_MODELS = [
-    'site', 'region', 'rack', 'rackgroup', 'manufacturer', 'device',                # DCIM
+    'site', 'region', 'rack', 'rackgroup', 'manufacturer', 'devicetype', 'device',  # DCIM
     'consoleport', 'powerport', 'interfaceconnection',                              # DCIM
     'aggregate', 'prefix', 'ipaddress', 'vlan',                                     # IPAM
     'provider', 'circuit',                                                          # Circuits

+ 1 - 0
netbox/templates/_base.html

@@ -93,6 +93,7 @@
                             <li><a href="{% url 'dcim:devicetype_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Device Types</a></li>
                             {% if perms.dcim.add_devicetype %}
                                 <li><a href="{% url 'dcim:devicetype_add' %}"><i class="fa fa-plus" aria-hidden="true"></i> Add a Device Type</a></li>
+                                <li><a href="{% url 'dcim:devicetype_import' %}"><i class="fa fa-download" aria-hidden="true"></i> Import Device Types</a></li>
                             {% endif %}
                             <li class="divider"></li>
                             <li><a href="{% url 'dcim:devicerole_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Device Roles</a></li>

+ 5 - 0
netbox/templates/dcim/devicetype_list.html

@@ -10,7 +10,12 @@
             <span class="fa fa-plus" aria-hidden="true"></span>
             Add a device type
         </a>
+        <a href="{% url 'dcim:devicetype_import' %}" class="btn btn-info">
+            <span class="fa fa-download" aria-hidden="true"></span>
+            Import device types
+        </a>
     {% endif %}
+    {% include 'inc/export_button.html' with obj_type='devicetypes' %}
 </div>
 <h1>Device Types</h1>
 <div class="row">