1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Fixes #764: Encapsulate in double quotes values containing commas when exporting to CSV

This commit is contained in:
Jeremy Stretch
2017-01-04 10:47:00 -05:00
parent 8154ae3685
commit 52567c4ade
5 changed files with 80 additions and 61 deletions

View File

@ -5,6 +5,7 @@ from django.db import models
from dcim.fields import ASNField
from extras.models import CustomFieldModel, CustomFieldValue
from tenancy.models import Tenant
from utilities.utils import csv_format
from utilities.models import CreatedUpdatedModel
@ -57,10 +58,10 @@ class Provider(CreatedUpdatedModel, CustomFieldModel):
return reverse('circuits:provider', args=[self.slug])
def to_csv(self):
return ','.join([
return csv_format([
self.name,
self.slug,
str(self.asn) if self.asn else '',
self.asn,
self.account,
self.portal_url,
])
@ -68,7 +69,7 @@ class Provider(CreatedUpdatedModel, CustomFieldModel):
class CircuitType(models.Model):
"""
Circuits can be orgnanized by their functional role. For example, a user might wish to define CircuitTypes named
Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
"Long Haul," "Metro," or "Out-of-Band".
"""
name = models.CharField(max_length=50, unique=True)
@ -110,13 +111,13 @@ class Circuit(CreatedUpdatedModel, CustomFieldModel):
return reverse('circuits:circuit', args=[self.pk])
def to_csv(self):
return ','.join([
return csv_format([
self.cid,
self.provider.name,
self.type.name,
self.tenant.name if self.tenant else '',
self.install_date.isoformat() if self.install_date else '',
str(self.commit_rate) if self.commit_rate else '',
self.tenant.name if self.tenant else None,
self.install_date.isoformat() if self.install_date else None,
self.commit_rate,
])
def _get_termination(self, side):

View File

@ -16,6 +16,7 @@ from tenancy.models import Tenant
from utilities.fields import ColorField, NullableCharField
from utilities.managers import NaturalOrderByManager
from utilities.models import CreatedUpdatedModel
from utilities.utils import csv_format
from .fields import ASNField, MACAddressField
@ -263,12 +264,12 @@ class Site(CreatedUpdatedModel, CustomFieldModel):
return reverse('dcim:site', args=[self.slug])
def to_csv(self):
return ','.join([
return csv_format([
self.name,
self.slug,
self.tenant.name if self.tenant else '',
self.tenant.name if self.tenant else None,
self.facility,
str(self.asn) if self.asn else '',
self.asn,
self.contact_name,
self.contact_phone,
self.contact_email,
@ -398,17 +399,17 @@ class Rack(CreatedUpdatedModel, CustomFieldModel):
})
def to_csv(self):
return ','.join([
return csv_format([
self.site.name,
self.group.name if self.group else '',
self.group.name if self.group else None,
self.name,
self.facility_id or '',
self.tenant.name if self.tenant else '',
self.role.name if self.role else '',
self.get_type_display() if self.type else '',
str(self.width),
str(self.u_height),
'True' if self.desc_units else '',
self.facility_id,
self.tenant.name if self.tenant else None,
self.role.name if self.role else None,
self.get_type_display() if self.type else None,
self.width,
self.u_height,
self.desc_units,
])
@property
@ -910,19 +911,19 @@ class Device(CreatedUpdatedModel, CustomFieldModel):
Device.objects.filter(parent_bay__device=self).update(rack=self.rack)
def to_csv(self):
return ','.join([
return csv_format([
self.name or '',
self.device_role.name,
self.tenant.name if self.tenant else '',
self.tenant.name if self.tenant else None,
self.device_type.manufacturer.name,
self.device_type.model,
self.platform.name if self.platform else '',
self.platform.name if self.platform else None,
self.serial,
self.asset_tag if self.asset_tag else '',
self.asset_tag,
self.rack.site.name,
self.rack.name,
str(self.position) if self.position else '',
self.get_face_display() or '',
self.position,
self.get_face_display(),
])
@property
@ -991,9 +992,9 @@ class ConsolePort(models.Model):
# Used for connections export
def to_csv(self):
return ','.join([
self.cs_port.device.identifier if self.cs_port else '',
self.cs_port.name if self.cs_port else '',
return csv_format([
self.cs_port.device.identifier if self.cs_port else None,
self.cs_port.name if self.cs_port else None,
self.device.identifier,
self.name,
self.get_connection_status_display(),
@ -1055,10 +1056,10 @@ class PowerPort(models.Model):
return self.device.get_absolute_url()
# Used for connections export
def to_csv(self):
def csv_format(self):
return ','.join([
self.power_outlet.device.identifier if self.power_outlet else '',
self.power_outlet.name if self.power_outlet else '',
self.power_outlet.device.identifier if self.power_outlet else None,
self.power_outlet.name if self.power_outlet else None,
self.device.identifier,
self.name,
self.get_connection_status_display(),
@ -1196,7 +1197,7 @@ class InterfaceConnection(models.Model):
# Used for connections export
def to_csv(self):
return ','.join([
return csv_format([
self.interface_a.device.identifier,
self.interface_a.name,
self.interface_b.device.identifier,

View File

@ -13,6 +13,7 @@ from extras.models import CustomFieldModel, CustomFieldValue
from tenancy.models import Tenant
from utilities.models import CreatedUpdatedModel
from utilities.sql import NullsFirstQuerySet
from utilities.utils import csv_format
from .fields import IPNetworkField, IPAddressField
@ -95,11 +96,11 @@ class VRF(CreatedUpdatedModel, CustomFieldModel):
return reverse('ipam:vrf', args=[self.pk])
def to_csv(self):
return ','.join([
return csv_format([
self.name,
self.rd,
self.tenant.name if self.tenant else '',
'True' if self.enforce_unique else '',
self.tenant.name if self.tenant else None,
self.enforce_unique,
self.description,
])
@ -183,10 +184,10 @@ class Aggregate(CreatedUpdatedModel, CustomFieldModel):
super(Aggregate, self).save(*args, **kwargs)
def to_csv(self):
return ','.join([
str(self.prefix),
return csv_format([
self.prefix,
self.rir.name,
self.date_added.isoformat() if self.date_added else '',
self.date_added.isoformat() if self.date_added else None,
self.description,
])
@ -319,16 +320,16 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
super(Prefix, self).save(*args, **kwargs)
def to_csv(self):
return ','.join([
str(self.prefix),
self.vrf.rd if self.vrf else '',
self.tenant.name if self.tenant else '',
self.site.name if self.site else '',
self.vlan.group.name if self.vlan and self.vlan.group else '',
str(self.vlan.vid) if self.vlan else '',
return csv_format([
self.prefix,
self.vrf.rd if self.vrf else None,
self.tenant.name if self.tenant else None,
self.site.name if self.site else None,
self.vlan.group.name if self.vlan and self.vlan.group else None,
self.vlan.vid if self.vlan else None,
self.get_status_display(),
self.role.name if self.role else '',
'True' if self.is_pool else '',
self.role.name if self.role else None,
self.is_pool,
self.description,
])
@ -432,14 +433,14 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel):
elif self.family == 6 and getattr(self, 'primary_ip6_for', False):
is_primary = True
return ','.join([
str(self.address),
self.vrf.rd if self.vrf else '',
self.tenant.name if self.tenant else '',
return csv_format([
self.address,
self.vrf.rd if self.vrf else None,
self.tenant.name if self.tenant else None,
self.get_status_display(),
self.device.identifier if self.device else '',
self.interface.name if self.interface else '',
'True' if is_primary else '',
self.device.identifier if self.device else None,
self.interface.name if self.interface else None,
is_primary,
self.description,
])
@ -523,14 +524,14 @@ class VLAN(CreatedUpdatedModel, CustomFieldModel):
})
def to_csv(self):
return ','.join([
return csv_format([
self.site.name,
self.group.name if self.group else '',
str(self.vid),
self.group.name if self.group else None,
self.vid,
self.name,
self.tenant.name if self.tenant else '',
self.tenant.name if self.tenant else None,
self.get_status_display(),
self.role.name if self.role else '',
self.role.name if self.role else None,
self.description,
])

View File

@ -4,6 +4,7 @@ from django.db import models
from extras.models import CustomFieldModel, CustomFieldValue
from utilities.models import CreatedUpdatedModel
from utilities.utils import csv_format
class TenantGroup(models.Model):
@ -45,9 +46,9 @@ class Tenant(CreatedUpdatedModel, CustomFieldModel):
return reverse('tenancy:tenant', args=[self.slug])
def to_csv(self):
return ','.join([
return csv_format([
self.name,
self.slug,
self.group.name if self.group else '',
self.group.name if self.group else None,
self.description,
])

15
netbox/utilities/utils.py Normal file
View File

@ -0,0 +1,15 @@
def csv_format(data):
"""
Encapsulate any data which contains a comma within double quotes.
"""
csv = []
for d in data:
if d in [None, False]:
csv.append(u'')
elif type(d) not in (str, unicode):
csv.append(u'{}'.format(d))
elif u',' in d:
csv.append(u'"{}"'.format(d))
else:
csv.append(d)
return u','.join(csv)