diff --git a/netbox/circuits/models.py b/netbox/circuits/models.py index 7da5c4f73e2..44018ae1cea 100644 --- a/netbox/circuits/models.py +++ b/netbox/circuits/models.py @@ -52,6 +52,8 @@ class Provider(CreatedUpdatedModel, CustomFieldModel): comments = models.TextField(blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') + csv_headers = ['name', 'slug', 'asn', 'account', 'portal_url'] + class Meta: ordering = ['name'] @@ -107,6 +109,8 @@ class Circuit(CreatedUpdatedModel, CustomFieldModel): comments = models.TextField(blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') + csv_headers = ['cid', 'provider', 'type', 'tenant', 'install_date', 'commit_rate', 'description'] + class Meta: ordering = ['provider', 'cid'] unique_together = ['provider', 'cid'] diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index bbc27b8d9a0..6411c6bffbe 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -280,6 +280,10 @@ class Site(CreatedUpdatedModel, CustomFieldModel): objects = SiteManager() + csv_headers = [ + 'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'contact_name', 'contact_phone', 'contact_email', + ] + class Meta: ordering = ['name'] @@ -402,6 +406,10 @@ class Rack(CreatedUpdatedModel, CustomFieldModel): objects = RackManager() + csv_headers = [ + 'site', 'group_name', 'name', 'facility_id', 'tenant', 'role', 'type', 'width', 'u_height', 'desc_units', + ] + class Meta: ordering = ['site', 'name'] unique_together = [ @@ -981,6 +989,11 @@ class Device(CreatedUpdatedModel, CustomFieldModel): objects = DeviceManager() + csv_headers = [ + 'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag', 'status', + 'site', 'rack_group', 'rack_name', 'position', 'face', + ] + class Meta: ordering = ['name'] unique_together = ['rack', 'position', 'face'] @@ -1096,6 +1109,7 @@ def to_csv(self): self.asset_tag, self.get_status_display(), self.site.name, + self.rack.group.name if self.rack and self.rack.group else None, self.rack.name if self.rack else None, self.position, self.get_face_display(), @@ -1162,6 +1176,8 @@ class ConsolePort(models.Model): verbose_name='Console server port', blank=True, null=True) connection_status = models.NullBooleanField(choices=CONNECTION_STATUS_CHOICES, default=CONNECTION_STATUS_CONNECTED) + csv_headers = ['console_server', 'cs_port', 'device', 'console_port', 'connection_status'] + class Meta: ordering = ['device', 'name'] unique_together = ['device', 'name'] @@ -1231,6 +1247,8 @@ class PowerPort(models.Model): blank=True, null=True) connection_status = models.NullBooleanField(choices=CONNECTION_STATUS_CHOICES, default=CONNECTION_STATUS_CONNECTED) + csv_headers = ['pdu', 'power_outlet', 'device', 'power_port', 'connection_status'] + class Meta: ordering = ['device', 'name'] unique_together = ['device', 'name'] @@ -1392,6 +1410,8 @@ class InterfaceConnection(models.Model): connection_status = models.BooleanField(choices=CONNECTION_STATUS_CHOICES, default=CONNECTION_STATUS_CONNECTED, verbose_name='Status') + csv_headers = ['device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status'] + def clean(self): try: if self.interface_a == self.interface_b: diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 40e3fefdef9..89ee0facc83 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -89,6 +89,8 @@ class VRF(CreatedUpdatedModel, CustomFieldModel): description = models.CharField(max_length=100, blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') + csv_headers = ['name', 'rd', 'tenant', 'enforce_unique', 'description'] + class Meta: ordering = ['name'] verbose_name = 'VRF' @@ -146,6 +148,8 @@ class Aggregate(CreatedUpdatedModel, CustomFieldModel): description = models.CharField(max_length=100, blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') + csv_headers = ['prefix', 'rir', 'date_added', 'description'] + class Meta: ordering = ['family', 'prefix'] @@ -297,6 +301,10 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel): objects = PrefixQuerySet.as_manager() + csv_headers = [ + 'prefix', 'vrf', 'tenant', 'site', 'vlan_group', 'vlan_vid', 'status', 'role', 'is_pool', 'description', + ] + class Meta: ordering = ['vrf', 'family', 'prefix'] verbose_name_plural = 'prefixes' @@ -424,6 +432,8 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel): objects = IPAddressManager() + csv_headers = ['address', 'vrf', 'tenant', 'status', 'device', 'interface_name', 'is_primary', 'description'] + class Meta: ordering = ['family', 'address'] verbose_name = 'IP address' @@ -462,11 +472,12 @@ def save(self, *args, **kwargs): def to_csv(self): # Determine if this IP is primary for a Device - is_primary = False if self.family == 4 and getattr(self, 'primary_ip4_for', False): is_primary = True elif self.family == 6 and getattr(self, 'primary_ip6_for', False): is_primary = True + else: + is_primary = False return csv_format([ self.address, @@ -537,6 +548,8 @@ class VLAN(CreatedUpdatedModel, CustomFieldModel): description = models.CharField(max_length=100, blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') + csv_headers = ['site', 'group_name', 'vid', 'name', 'tenant', 'status', 'role', 'description'] + class Meta: ordering = ['site', 'group', 'vid'] unique_together = [ diff --git a/netbox/secrets/models.py b/netbox/secrets/models.py index bf423fdf637..e8eb2ff4562 100644 --- a/netbox/secrets/models.py +++ b/netbox/secrets/models.py @@ -291,6 +291,7 @@ class Secret(CreatedUpdatedModel): hash = models.CharField(max_length=128, editable=False) plaintext = None + csv_headers = ['device', 'role', 'name', 'plaintext'] class Meta: ordering = ['device', 'role', 'name'] diff --git a/netbox/tenancy/models.py b/netbox/tenancy/models.py index ea3405df98b..a43327a06f8 100644 --- a/netbox/tenancy/models.py +++ b/netbox/tenancy/models.py @@ -41,6 +41,8 @@ class Tenant(CreatedUpdatedModel, CustomFieldModel): comments = models.TextField(blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') + csv_headers = ['name', 'slug', 'group', 'description'] + class Meta: ordering = ['group', 'name'] diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index 7e95469f1bf..223ef43a943 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -102,7 +102,9 @@ def get(self, request): .format(et.name)) # Fall back to built-in CSV export elif 'export' in request.GET and hasattr(model, 'to_csv'): - output = '\n'.join([obj.to_csv() for obj in self.queryset]) + headers = getattr(model, 'csv_headers', None) + output = ','.join(headers) + '\n' if headers else '' + output += '\n'.join([obj.to_csv() for obj in self.queryset]) response = HttpResponse( output, content_type='text/csv'